• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 200, comments - 8, trackbacks - 0, articles - 0
            list_for_each遍歷子進程方法,順便分析下container_of宏的實現過程

            Linux系統中的每個進程都有一個父進程(init進程除外);每個進程還有0個或多個子進程。在進程描述符中parent指針指向其父進程,還有一個名為children的子進程鏈表(父進程task_struct中的children相當于鏈表的表頭)。
            而我們可以使用list_for_each(/include/linux/list.h)來依次遍歷訪問子進程:
            1. struct task_struct *task;
            2. struct list_head *list;
            3. list_for_each(list, &current->children) {
            4.       task = list_entry(list, struct task_struct, sibling);
            5. }
            其中task即為某個子進程的地址
            首先需要說明一點task_struct中的children指針指向其某個子進程的進程描述符task_struct中children的地址,而非直接指向某個子進程的地址,也就是說子進程鏈表中存放的僅僅是各個task_struct成員children的地址。
            我們查看源文件找到list_for_each的定義:
            1. #define list_for_each(pos, head) \
            2.         for (pos = (head)->next; prefetch(pos->next), pos != (head); \
            3.                 pos = pos->next)
            從上可以看出list_for_each其實就是一個for循環,在網上看到prefetch()是一個預抓取的函數,我并不理解它(哪位大牛知道的講下哦),不過這個對for()并沒有多大的影響。for()實現的就是一個children鏈表的遍歷,而由children的地址如何取到task_struct的地址呢,它是由list_entry宏來實現的。
            我們先給出所需函數或宏的源代碼
            1. list_entry(/include/linux/list.h)
            2. #define list_entry(ptr, type, member) \
            3.         container_of(ptr, type, member)
            4. ---------------------------------------------------
            5. container_of(include/linux/kernel.h)
            6. #define container_of(ptr, type, member) ({                        \
            7.         const typeof( ((type *)0)->member ) *__mptr = (ptr);        \
            8.         (type *)( (char *)__mptr - offsetof(type,member) );})
            9. -------------------------------------------
            10. offsetof(/include/linux/stddef.h)
            11. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
            對于list_entry宏來說ptr在這里為指向children鏈表的指針,type為task_struct結構體的類型,member為鏈表成員的變量名,即children。
            container_of()思路為先求出結構體成員member(即children)在結構體(即task_struct)中的偏移量,然后再根據member的地址(即ptr)來求出結構體(即task_struct)的地址。

            哇哈哈  下面是我覺得最經典的地方((type *)0)->member,他將地址0強制轉換為type類型的指針,然后再指向成員member,此時((type *)0)->member的地址即為member成員相對于結構體的位移。
            其中typeof()相當于C的sizeof(),(char *)__mptr這個強制轉換用來計算偏移字節量,size_t被定義為unsigned int 類型。



                   這樣這個過程就不難理解了吧


            PS:網上找到的list_entry宏定義的另一個版本(有人說是老版本kernel里面的),其實是一樣的,大家自己理解吧。^_^
            #define list_entry(ptr, type, member) \ 
            ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 
            AV色综合久久天堂AV色综合在| 国产∨亚洲V天堂无码久久久| 久久91精品久久91综合| 国产亚洲精品美女久久久| 狠狠色丁香久久综合婷婷| 国产精品免费看久久久香蕉| 色偷偷88欧美精品久久久| 一本色道久久综合狠狠躁| 久久精品国产亚洲沈樵| 国产精品久久久久久久app| 久久亚洲精精品中文字幕| 一本一道久久精品综合| 久久笫一福利免费导航| 婷婷综合久久狠狠色99h| 偷偷做久久久久网站| 91精品国产综合久久四虎久久无码一级| 久久久中文字幕日本| 久久亚洲精品中文字幕| 久久精品免费大片国产大片| 亚洲精品乱码久久久久久蜜桃不卡| 色综合久久最新中文字幕| 亚洲精品乱码久久久久久蜜桃不卡| 久久久久久国产精品免费免费| 久久人人爽人人爽人人AV| 久久久久亚洲AV综合波多野结衣 | 色99久久久久高潮综合影院 | 爱做久久久久久| 奇米综合四色77777久久| 久久天天婷婷五月俺也去| 伊人丁香狠狠色综合久久| 精品久久8x国产免费观看| 亚洲精品无码久久久久去q| 一级做a爰片久久毛片免费陪| 久久99精品免费一区二区| 99久久婷婷国产一区二区| 91精品观看91久久久久久| 久久九九亚洲精品| 伊人久久精品线影院| 国产激情久久久久影院老熟女| 欧美一区二区精品久久| 中文字幕成人精品久久不卡|