■
今日からapacheのコード(httpd2.2.4)を読んで行き、メモ代わりにブログに書こうと思う。
まずはAPRの基本構造であるAPR_RINGから。
#define APR_RING_ENTRY(elem) \ struct { \ struct elem *next; \ struct elem *prev; \ }
このdoubly linked listを必要な構造体に挿入してる
#define APR_RING_HEAD(head, elem) \ struct head { \ struct elem *next; \ struct elem *prev; \ }
これは先ほどのdoubly linked listの先頭(終端)としてつなげて、
これ自体はリングのデータにならず、番兵(sentinel)として働く
* @param hp The head of the ring * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct #define APR_RING_SENTINEL(hp, elem, link) \ (struct elem *)((char *)(hp) - APR_OFFSETOF(struct elem, link))
APR_OFFSETOFは構造体struct elemの先頭からlinkまでのバイト数
hpはリングのheadだけどそれが使われている構造体上では途中の位置に
あり、その位置はAPR_OFFSETOF(struct elem, link)となる。
よって上記のAPR_RING_SENTINELは検査している構造体上のトップになる。
#define APR_RING_FIRST(hp) (hp)->next #define APR_RING_LAST(hp) (hp)->prev #define APR_RING_NEXT(ep, link) (ep)->link.next #define APR_RING_PREV(ep, link) (ep)->link.prev
hpはheadでepはカレントelement。
#define APR_RING_INIT(hp, elem, link) do { \ APR_RING_FIRST((hp)) = APR_RING_SENTINEL((hp), elem, link); \ APR_RING_LAST((hp)) = APR_RING_SENTINEL((hp), elem, link); \ } while (0)
なぜdo while? しかも条件が0なので1回しか行われない。
アセンブラレベルでの何らかの最適化?
/** * Splice the sequence ep1..epN into the ring before element lep * (..lep.. becomes ..ep1..epN..lep..) * @warning This doesn't work for splicing before the first element or on * empty rings... see APR_RING_SPLICE_HEAD for one that does * @param lep Element in the ring to splice before * @param ep1 First element in the sequence to splice in * @param epN Last element in the sequence to splice in * @param link The name of the APR_RING_ENTRY in the element struct */ #define APR_RING_SPLICE_BEFORE(lep, ep1, epN, link) do { \ APR_RING_NEXT((epN), link) = (lep); \ APR_RING_PREV((ep1), link) = APR_RING_PREV((lep), link); \ APR_RING_NEXT(APR_RING_PREV((lep), link), link) = (ep1); \ APR_RING_PREV((lep), link) = (epN); \ } while (0)
ringへのelementの挿入。
linkはAPR_RING_ENTRYの位置
注入するringの先頭がep1で最後がepN。要するにep1〜epNのつながりを
lepの前に挿入する。
#define APR_RING_INSERT_TAIL(hp, nep, elem, link) \ APR_RING_SPLICE_TAIL((hp), (nep), (nep), elem, link)
headの最後(tail)にnepを挿入する
#define APR_RING_INSERT_HEAD(hp, nep, elem, link) \ APR_RING_SPLICE_HEAD((hp), (nep), (nep), elem, link)
headの先頭にnepを挿入する
/** * Concatenate ring h2 onto the end of ring h1, leaving h2 empty. * @param h1 Head of the ring to concatenate onto * @param h2 Head of the ring to concatenate * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */ #define APR_RING_CONCAT(h1, h2, elem, link) do { \ if (!APR_RING_EMPTY((h2), elem, link)) { \ APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((h1), elem, link), \ APR_RING_FIRST((h2)), \ APR_RING_LAST((h2)), link); \ APR_RING_INIT((h2), elem, link); \ } \ } while (0)
head h2をh1の前に繋げる(concat)
/** * Prepend ring h2 onto the beginning of ring h1, leaving h2 empty. * @param h1 Head of the ring to prepend onto * @param h2 Head of the ring to prepend * @param elem The name of the element struct * @param link The name of the APR_RING_ENTRY in the element struct */ #define APR_RING_PREPEND(h1, h2, elem, link) do { \ if (!APR_RING_EMPTY((h2), elem, link)) { \ APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((h1), elem, link), \ APR_RING_FIRST((h2)), \ APR_RING_LAST((h2)), link); \ APR_RING_INIT((h2), elem, link); \ } \ } while (0)
これはさっきのconcatと違ってAPR_RING_SPLICE_AFTERなのでhp1の次にh2つなげる
/** * Unsplice a sequence of elements from a ring * @warning The unspliced sequence is left with dangling pointers at either end * @param ep1 First element in the sequence to unsplice * @param epN Last element in the sequence to unsplice * @param link The name of the APR_RING_ENTRY in the element struct */ #define APR_RING_UNSPLICE(ep1, epN, link) do { \ APR_RING_NEXT(APR_RING_PREV((ep1), link), link) = \ APR_RING_NEXT((epN), link); \ APR_RING_PREV(APR_RING_NEXT((epN), link), link) = \ APR_RING_PREV((ep1), link); \ } while (0)
ep1からepNをこのリング構造から外す
/** * Remove a single element from a ring * @warning The unspliced element is left with dangling pointers at either end * @param ep Element to remove * @param link The name of the APR_RING_ENTRY in the element struct */ #define APR_RING_REMOVE(ep, link) \ APR_RING_UNSPLICE((ep), (ep), link)
epをこのリング構造から外す