メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2008年2月14日木曜日

[Apache][CodeReading] Apache2.2.8コードリーディング14日目(2)

本日2回目のApacheコードリーディング。

本日片付けたものは以下のとおり。

  • apr_palloc()/Apache2.2.8
  • list_insertマクロ/Apache2.2.8
  • list_removeマクロ/Apache2.2.8
  • hash_mutexスタティック変数/Apache2.2.8
  • apr_pool_tag()/Apache2.2.8
  • apr_allocator_destroy()/Apache2.2.8
  • MAX_INDEXローカル定数/Apache2.2.8
  • apr_pool_create_ex()/Apache2.2.8
  • apr_allocator_mutex_get()/Apache2.2.8
  • NETWARE定数/Apache2.2.8
  • SIZEOF_POOL_Tローカルマクロ/Apache2.2.8
Apacheのコードリーディングというよりも、むしろAPRのコードリーディングな感じ。

list_insert、list_remove、apr_pool_create_exは先ほどやったので、その続きから。
hash_mutexについては存在を知っただけ。これがいったい何に使われるのかは今のところ不明。
恐らくapr_atomic_initを読むとわかると思う。

apr_allocator_destroy()

125 APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator)
126 {
127 apr_uint32_t index;
128 apr_memnode_t *node, **ref;
129
130 for (index = 0; index < MAX_INDEX; index++) {
131 ref = &allocator->free[index];
132 while ((node = *ref) != NULL) {
133 *ref = node->next;
134 free(node);
135 }
136 }
137
138 free(allocator);
139 }


特筆すべきことはない。
アロケータのfree[]を全て解放し、アロケータ自身も解放しているだけ。

apr_pool_tag()

1888 APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag)
1889 {
1890 pool->tag = tag;
1891 }


これも特になし。pool->tagのアクセサ。


apr_allocator_mutex_get()

148 APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get(
149 apr_allocator_t *allocator)
150 {
151 return allocator->mutex;
152 }


これも同様。


apr_palloc()
やはりメインはこれ。

623 APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size)
624 {
625 apr_memnode_t *active, *node;
626 void *mem;
627 apr_size_t free_index;
628
629 size = APR_ALIGN_DEFAULT(size);
630 active = pool->active;
631
632 /* If the active node has enough bytes left, use it. */
633 if (size < (apr_size_t)(active->endp - active->first_avail)) {
634 mem = active->first_avail;
635 active->first_avail += size;
636
637 return mem;
638 }
639
640 node = active->next;
641 if (size < (apr_size_t)(node->endp - node->first_avail)) {
642 list_remove(node);
643 }
644 else {
645 if ((node = allocator_alloc(pool->allocator, size)) == NULL) {
646 if (pool->abort_fn)
647 pool->abort_fn(APR_ENOMEM);
648
649 return NULL;
650 }
651 }
652
653 node->free_index = 0;
654
655 mem = node->first_avail;
656 node->first_avail += size;
657
658 list_insert(node, active);
659
660 pool->active = node;
661
662 free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
663 BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
664
665 active->free_index = (APR_UINT32_TRUNC_CAST)free_index;
666 node = active->next;
667 if (free_index >= node->free_index)
668 return mem;
669
670 do {
671 node = node->next;
672 }
673 while (free_index < free_index);
674
675 list_remove(active);
676 list_insert(active, node);
677
678 return mem;
679 }


これを見ればわかるとおり、poolのactiveメンバがnodeのリストになっていて、そのnodeリストのnodeから
メモリ領域を確保している。
開き領域がnodeリスト中になければ新しくnodeを作成し、activeリストにつなぐ。
[Apache][CodeReading] Apache2.2.8の13日目に挙げた疑問のひとつもここで解決する。

[疑問]endpの使い道は何か。


ずばり答えは、

サイズを取得するために使う。


である。
まぁ、そうだろうな。

634行目~635行目、655行目~656行目にあるとおり、メモリ割り当てを行うたびに
first_availの値は増えていく。
これも、[Apache][CodeReading] Apache2.2.8の13日目に、

何も考えずに使うとするとfree[1]ばかりが出来そうだ


との考えを否定してくれている。
allocator_alloc()で割り当てた最小8192バイトの領域は、このapr_palloc()で細切れに使用される。
また、使用領域は常に8バイトアライン。


そして、pool->activeのリストにも順番があって、その辺の順番を維持しているのが、
662行目~676行目のところ。
ここからpool->activeリストは空き容量が大きいもの(free_indexの値が大きいもの)から降順にならんでいることが分かる。
降順に並べることで、pool->activeの持っているリストの中に空き容量があるものが入っているかどうかを、先頭の要素を調べるだけで判断できるようになっている。



今日はここまで。
まだcurrent_free_indexが何なのか不明なのが気持ち悪いが、
メモリ周りは面白いねー。
次はapr_atomic_initを読む、と思う
.

0 コメント: