ウォンツテック

そでやまのーと

今日から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をこのリング構造から外す