LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1202|回复: 2

struct zone结构中的等待队列问题求教。

[复制链接]
发表于 2010-4-26 09:58:03 | 显示全部楼层 |阅读模式
在struct zone有这样几个成员变量:
struct zone {
......//省略
         * wait_table           -- the array holding the hash table
         * wait_table_hash_nr_entries   -- the size of the hash table array
         * wait_table_bits      -- wait_table_size == (1 << wait_table_bits)
         *
         * The purpose of all these is to keep track of the people
         * waiting for a page to become available and make them
         * runnable again when possible. The trouble is that this
         * consumes a lot of space, especially when so few things
         * wait on pages at a given time. So instead of using
         * per-page waitqueues, we use a waitqueue hash table.
         *
         * The bucket discipline is to sleep on the same queue when
         * colliding and wake all in that wait queue when removing.
         * When something wakes, it must check to be sure its page is
         * truly available, a la thundering herd. The cost of a
         * collision is great, but given the expected load of the
         * table, they should be so rare as to be outweighed by the
         * benefits from the saved space.
         *
         * __wait_on_page_locked() and unlock_page() in mm/filemap.c, are the
         * primary users of these fields, and in mm/page_alloc.c
         * free_area_init_core() performs the initialization of them.
         */
        wait_queue_head_t       * wait_table;
        unsigned long           wait_table_hash_nr_entries;
        unsigned long           wait_table_bits;
.......//省略
}


根据结构中的注释:
wait_table是一个数组,类型是wait_queue_head_t,该数组的成员格数是 wait_table_hash_nr_entries.
并且我在源码[2.6.24]mm/page_alloc.c中也找到对应的初始化代码:
        ......
        zone->wait_table_hash_nr_entries =
                 wait_table_hash_nr_entries(zone_size_pages);
        zone->wait_table_bits =
                wait_table_bits(zone->wait_table_hash_nr_entries);
        alloc_size = zone->wait_table_hash_nr_entries
                                        * sizeof(wait_queue_head_t);

        if (system_state == SYSTEM_BOOTING) {
                zone->wait_table = (wait_queue_head_t *)
                        alloc_bootmem_node(pgdat, alloc_size);
        ......

而对成员wait_table_bits是啥东西就不明白了。上面的解释是wait_table_size == (1 << wait_table_bits),但是我觉得:zone->wait_table_hash_nr_entries*sizeof(wait_queue_head_t) 就可以得到表的大小了,何必要用wait_table_size?
发表于 2010-4-29 11:29:24 | 显示全部楼层

用于计算Hash值

(1)zone->wait_table_bits存放的内容,是从zone->wait_table_hash_nr_entries
   推导得出的。
   zone->wait_table_bits = (从低位算,第一个Bit为1的位)(zone->wait_table_hash_nr_entries);


(2)由zone->wait_table_bits,及虚拟内存地址,获得数组zone->wait_table某个子项。
   例如,把虚拟内存地址,向右移动(32-zone->wait_table_bits)位后,获得某个其子项。
   
(3)zone->wait_table_bits记录的是位数,2的zone->wait_table_bits次方,有可能是
   zone->wait_table_hash_nr_entries,获得一个Hash值的同时,保证不能越界访问
   数组zone->wait_table
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-4-29 17:29:39 | 显示全部楼层
多谢你的解析。

我有看了一遍相关代码。其中zone->wait_table_hash_nr_entries一定是2的n次幂。在函数
static inline unsigned long wait_table_hash_nr_entries(unsigned long pages)
{
        unsigned long size = 1;

        pages /= PAGES_PER_WAITQUEUE;
        
        while (size < pages)
                size <<= 1;

        /*
         * Once we have dozens or even hundreds of threads sleeping
         * on IO we've got bigger problems than wait queue collision.
         * Limit the size of the wait table to a reasonable size.
         */
        size = min(size, 4096UL);

        return max(size, 4UL);
}

所以最后得到的hash表的大小[也就是zone->wait_table数组的大小]一定是2的zone->wait_table_bits次幂。也就是说
1<<zone->wait_table_bits == zone->wait_table_hash_nr_entries

在计算hash函数hash_long中, 通过对某个32位地址 >> (32-zone->wait_table_bits)
求出的是该虚拟地址对应的hash表的索引值。 同时也保证了越界的问题。

真实太感谢了。好几个论坛都发帖了。都没人回,可焦急啊。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表