国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
linux內(nèi)核之hlist


linux內(nèi)核hlist分析

在Linux內(nèi)核中,hlist(哈希鏈表)使用非常廣泛。本文將對(duì)其數(shù)據(jù)結(jié)構(gòu)和核心函數(shù)進(jìn)行分析。

和hlist相關(guān)的數(shù)據(jù)結(jié)構(gòu)有兩個(gè)

(1) hlist_head

 struct hlist_head {
         struct hlist_node *first;
 };

(2) hlist_node

 struct hlist_node {
         struct hlist_node *next, **pprev;
 };

顧名思義, hlist_head表示哈希表的頭結(jié)點(diǎn)。 哈希表中每一個(gè)entry(hlist_head)所對(duì)應(yīng)的都是一個(gè)鏈表(hlist),該鏈表的結(jié)點(diǎn)由hlist_node表示。

hlist_head結(jié)構(gòu)體只有一個(gè)域,即first。 first指針指向該hlist鏈表的第一個(gè)節(jié)點(diǎn)。

hlist_node結(jié)構(gòu)體有兩個(gè)域,next 和pprev。 next指針很容易理解,它指向下個(gè)hlist_node結(jié)點(diǎn),倘若該節(jié)點(diǎn)是鏈表的最后一個(gè)節(jié)點(diǎn),next指向NULL。

pprev是一個(gè)二級(jí)指針, 它指向前一個(gè)節(jié)點(diǎn)的next指針。為什么我們需要這樣一個(gè)指針呢?它的好處是什么?

在回答這個(gè)問(wèn)題之前,我們先研究另一個(gè)問(wèn)題:為什么散列表的實(shí)現(xiàn)需要兩個(gè)不同的數(shù)據(jù)結(jié)構(gòu)?

散列表的目的是為了方便快速的查找,所以散列表通常是一個(gè)比較大的數(shù)組,否則“沖突”的概率會(huì)非常大, 這樣也就失去了散列表的意義。如何做到既能維護(hù)一張大表,又能不使用過(guò)多的內(nèi)存呢?就只能從數(shù)據(jù)結(jié)構(gòu)上下功夫了。所以對(duì)于散列表的每個(gè)entry,它的結(jié)構(gòu)體中只存放一個(gè)指針,解決了占用空間的問(wèn)題。現(xiàn)在又出現(xiàn)了另一個(gè)問(wèn)題:數(shù)據(jù)結(jié)構(gòu)不一致。顯然,如果hlist_node采用傳統(tǒng)的next,prev指針, 對(duì)于第一個(gè)節(jié)點(diǎn)和后面其他節(jié)點(diǎn)的處理會(huì)不一致。這樣并不優(yōu)雅,而且效率上也有損失。

hlist_node巧妙地將pprev指向上一個(gè)節(jié)點(diǎn)的next指針的地址,由于hlist_head和hlist_node指向的下一個(gè)節(jié)點(diǎn)的指針類型相同,這樣就解決了通用性!

下面我們?cè)賮?lái)看一看hlist_node這樣設(shè)計(jì)之后,插入 刪除這些基本操作會(huì)有什么不一樣。

static inline void __hlist_del(struct hlist_node *n)
{
        struct hlist_node *next = n->next;
        struct hlist_node **pprev = n->pprev;
        *pprev = next;
        if (next)
                next->pprev = pprev;
}
__hlist_del用于刪除節(jié)點(diǎn)n。

首先獲取n的下一個(gè)節(jié)點(diǎn)next, n->pprev指向n的前一個(gè)節(jié)點(diǎn)的next指針的地址, 這樣×pprev就代表n前一個(gè)節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)(現(xiàn)在即n本身),第三行代碼*pprev=next;就將n的前一個(gè)節(jié)點(diǎn)和下一個(gè)節(jié)點(diǎn)關(guān)聯(lián)起來(lái)了。至此,n節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)的關(guān)聯(lián)工作就完成了,現(xiàn)在再來(lái)完成下一個(gè)節(jié)點(diǎn)的關(guān)聯(lián)工作。如果n是鏈表的最后一個(gè)節(jié)點(diǎn),那么n->next即為空, 則無(wú)需任何操作,否則,next->pprev = pprev。

給鏈表增加一個(gè)節(jié)點(diǎn)需要考慮兩個(gè)條件:(1)是否為鏈表的首個(gè)節(jié)點(diǎn)(2)普通節(jié)點(diǎn)。

 static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
 {
         struct hlist_node *first = h->first;
         n->next = first;
         if (first)
                 first->pprev = &n->next;
         h->first = n;
         n->pprev = &h->first;
 }
首先討論條件(1)。

first = h->first; 獲取當(dāng)前鏈表的首個(gè)節(jié)點(diǎn);

n->next = fist;  將n作為鏈表的首個(gè)節(jié)點(diǎn),讓first往后靠;

先來(lái)看最后一行 n->pprev - &h->first; 將n的pprev指向hlist_head的first指針,至此關(guān)于節(jié)點(diǎn)n的關(guān)聯(lián)工作就做完了。

再來(lái)看倒數(shù)第二行 h->first = n; 將節(jié)點(diǎn)h的關(guān)聯(lián)工作做完;

最后我們?cè)賮?lái)看原先的第一個(gè)節(jié)點(diǎn)的關(guān)聯(lián)工作,對(duì)于它來(lái)說(shuō),僅僅需要更新一下pprev的關(guān)聯(lián)信息: first->pprev = &n->next;

接下來(lái)討論條件(2)。 這里也包括兩種情況:a)插在當(dāng)前節(jié)點(diǎn)的前面b)插在當(dāng)前節(jié)點(diǎn)的后面

/* next must be != NULL */
 static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next)
 {
         n->pprev = next->pprev;
         n->next = next;
         next->pprev = &n->next;
         *(n->pprev) = n;
 }

先討論情況a) 將節(jié)點(diǎn)n 插到next之前  (n是新插入的節(jié)點(diǎn))

還是一個(gè)一個(gè)節(jié)點(diǎn)的搞定(一共三個(gè)節(jié)點(diǎn)), 先搞定節(jié)點(diǎn)n

n->pprev = next->prev;   將 next 的pprev 賦值給n->pprev  n取代next的位置

n->next = next;   將next作為n的下一個(gè)節(jié)點(diǎn), 至此節(jié)點(diǎn)n的關(guān)聯(lián)動(dòng)作完成。

next->pprev = &n->next; next的關(guān)聯(lián)動(dòng)作完成。

*(n->pprev) = n;   n->pprev表示n的前一個(gè)節(jié)點(diǎn)的next指針; *(n->pprev)則表示n的前一個(gè)節(jié)點(diǎn)next指針?biāo)赶蛳乱粋€(gè)節(jié)點(diǎn)的內(nèi)容, 這里將n賦值給它,正好完成它的關(guān)聯(lián)工作。

 static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next)
 {
         next->next = n->next;
         n->next = next;
         next->pprev = &n->next;
         if (next->next)
                 next->next->pprev  = &next->next;
 }
再來(lái)看情況b) 將結(jié)點(diǎn)next插入到n之后 (next是新插入的節(jié)點(diǎn))

具體步驟就不分析了。 應(yīng)該也很容易。

下面我還要介紹一個(gè)函數(shù):

 static inline int hlist_unhashed(const struct hlist_node *h)
 {
         return !h->pprev;
 }
這個(gè)函數(shù)的目的是判斷該節(jié)點(diǎn)是否已經(jīng)存在hash表中。這里處理得很巧妙。 判斷前一個(gè)節(jié)點(diǎn)的next指向的地址是否為空。


最后我們看一個(gè)具體的例子,Linux內(nèi)核是如何管理pid的。(正好和上一篇介紹pid的文章相呼應(yīng):))   基于內(nèi)核3.0.3

內(nèi)核初始化時(shí)要調(diào)用pidhash_init()創(chuàng)建哈希表。 該函數(shù)會(huì)在 start_kernel()函數(shù)里被調(diào)用(init/main.c Line 509)

 void __init pidhash_init(void)
 {
         int i, pidhash_size;

         pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18,
                                            HASH_EARLY | HASH_SMALL,
                                            &pidhash_shift, NULL, 4096);
         pidhash_size = 1 << pidhash_shift;
 
         for (i = 0; i < pidhash_size; i++)
                 INIT_HLIST_HEAD(&pid_hash[i]);
 }
從這個(gè)函數(shù)可以看到內(nèi)核會(huì)在slab上分配一個(gè)大小為pidhash_size的數(shù)組,然后為每一個(gè)entry進(jìn)行初始化(INIT_HLIST_HEAD)

在alloc_pid函數(shù)里

 struct pid *alloc_pid(struct pid_namespace *ns)
 {
         struct pid *pid;
         enum pid_type type;
         int i, nr;
         struct pid_namespace *tmp;
         struct upid *upid;
 
         pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);  /* 在slab上分配pid結(jié)構(gòu)體 */
         if (!pid)
                 goto out;
 
         tmp = ns;
         for (i = ns->level; i >= 0; i--) {  /* 雖然這里是for循環(huán),實(shí)際只會(huì)運(yùn)行一次,因?yàn)楝F(xiàn)在只支持global namespace即ns->level=0 */
                 nr = alloc_pidmap(tmp);  /* 在各級(jí)pid_namespace上尋找并分配pid的值 */
                 if (nr < 0)
                         goto out_free;
 
                 pid->numbers[i].nr = nr;
                 pid->numbers[i].ns = tmp;
                 tmp = tmp->parent;
         }
 
         get_pid_ns(ns);
         pid->level = ns->level;
         atomic_set(&pid->count, 1);
         for (type = 0; type < PIDTYPE_MAX; ++type)
                 INIT_HLIST_HEAD(&pid->tasks[type]);   
 
         upid = pid->numbers + ns->level;
         spin_lock_irq(&pidmap_lock);
         for ( ; upid >= pid->numbers; --upid)
                 hlist_add_head_rcu(&upid->pid_chain,
                                 &pid_hash[pid_hashfn(upid->nr, upid->ns)]);   /* 將各級(jí)namespace中的upid插入pidhash的哈希表里 */
         spin_unlock_irq(&pidmap_lock);
 
 out:
         return pid;
 
 out_free:
         while (++i <= ns->level)
                 free_pidmap(pid->numbers + i);
 
         kmem_cache_free(ns->pid_cachep, pid);
         pid = NULL;
         goto out;
 }

Linux 內(nèi)核 hlist 詳解

在Linux內(nèi)核中,hlist(哈希鏈表)使用非常廣泛。本文將對(duì)其數(shù)據(jù)結(jié)構(gòu)和核心函數(shù)進(jìn)行分析。

和hlist相關(guān)的數(shù)據(jù)結(jié)構(gòu)有兩個(gè):hlist_head 和 hlist_node

//hash桶的頭結(jié)點(diǎn)
struct hlist_head {
    struct hlist_node *first;//指向每一個(gè)hash桶的第一個(gè)結(jié)點(diǎn)的指針
};
//hash桶的普通結(jié)點(diǎn)
struct hlist_node {
    struct hlist_node *next;//指向下一個(gè)結(jié)點(diǎn)的指針
    struct hlist_node **pprev;//指向上一個(gè)結(jié)點(diǎn)的next指針的地址
};
結(jié)構(gòu)如下圖所示:


hlist_head結(jié)構(gòu)體只有一個(gè)域,即first。 first指針指向該hlist鏈表的第一個(gè)節(jié)點(diǎn)。
hlist_node結(jié)構(gòu)體有兩個(gè)域,next 和pprev。 next指針很容易理解,它指向下個(gè)hlist_node結(jié)點(diǎn),倘若該節(jié)點(diǎn)是鏈表的最后一個(gè)節(jié)點(diǎn),next指向NULL。
pprev是一個(gè)二級(jí)指針, 它指向前一個(gè)節(jié)點(diǎn)的next指針的地址
。為什么我們需要這樣一個(gè)指針呢?它的好處是什么?
在回答這個(gè)問(wèn)題之前,我們先研究另一個(gè)問(wèn)題:為什么哈希表的實(shí)現(xiàn)需要兩個(gè)不同的數(shù)據(jù)結(jié)構(gòu)?
哈希表的目的是為了方便快速的查找,所以哈希表中hash桶的數(shù)量通常比較大,否則“沖突”的概率會(huì)非常大,這樣也就失去了哈希表的意義。如何做到既能維護(hù)一張大表,又能不使用過(guò)多的內(nèi)存呢?就只能從數(shù)據(jù)結(jié)構(gòu)上下功夫了。所以對(duì)于哈希表的每個(gè)hash桶,它的結(jié)構(gòu)體中只存放一個(gè)指針,解決了占用空間的問(wèn)題?,F(xiàn)在又出現(xiàn)了另一個(gè)問(wèn)題:數(shù)據(jù)結(jié)構(gòu)不一致。顯然,如果hlist_node采用傳統(tǒng)的next,prev指針,對(duì)于第一個(gè)節(jié)點(diǎn)和后面其他節(jié)點(diǎn)的處理會(huì)不一致。這樣并不優(yōu)雅,而且效率上也有損失。
hlist_node巧妙地將pprev指向上一個(gè)節(jié)點(diǎn)的next指針的地址,由于hlist_head的first域指向的結(jié)點(diǎn)類型和hlist_node指向的下一個(gè)結(jié)點(diǎn)的結(jié)點(diǎn)類型相同,這樣就解決了通用性!

如果要?jiǎng)h除hash桶對(duì)應(yīng)鏈表中的第一個(gè)普通結(jié)點(diǎn)

對(duì)應(yīng)的程序代碼如下:

static inline void __hlist_del(struct hlist_node *n)
{
 struct hlist_node *next = n->next; //獲取指向第二個(gè)普通結(jié)點(diǎn)的指針
 struct hlist_node **pprev = n->pprev; //保留待刪除的第一個(gè)結(jié)點(diǎn)的pprev域(即頭結(jié)點(diǎn)first域的地址),此時(shí) pprev = &first
 *pprev = next;
 /*
 因?yàn)閜prev = &first,所以*pprev = next,相當(dāng)于 first = next
 即將hash桶的頭結(jié)點(diǎn)指針指向原來(lái)的第二個(gè)結(jié)點(diǎn),如上圖中的黑線1
 */

 if (next) //如果第二個(gè)結(jié)點(diǎn)不為空
  next->pprev = pprev; //將第二個(gè)結(jié)點(diǎn)的pprev域設(shè)置為頭結(jié)點(diǎn)first域的地址,如上圖中的黑線2
}
如果要?jiǎng)h除hash桶對(duì)應(yīng)鏈表中的非第一個(gè)結(jié)點(diǎn)


對(duì)應(yīng)的程序代碼如下:

static inline void __hlist_del(struct hlist_node *n)
{
 struct hlist_node *next = n->next; //獲取指向待刪除結(jié)點(diǎn)的下一個(gè)普通結(jié)點(diǎn)的指針
 struct hlist_node **pprev = n->pprev; //獲取待刪除結(jié)點(diǎn)的pprev域
 *pprev = next; //修改待刪除結(jié)點(diǎn)的pprev域,邏輯上使待刪除結(jié)點(diǎn)的前驅(qū)結(jié)點(diǎn)指向待刪除結(jié)點(diǎn)的后繼結(jié)點(diǎn),如上圖中的黑線1

 if (next) //如果待刪除結(jié)點(diǎn)的下一個(gè)普通結(jié)點(diǎn)不為空
      next->pprev = pprev; //設(shè)置下一個(gè)結(jié)點(diǎn)的pprev域,如上圖中的黑線2,保持hlist的結(jié)構(gòu)
}
可以看到刪除第一個(gè)普通結(jié)點(diǎn)和刪除非第一個(gè)普通結(jié)點(diǎn)的代碼是一樣的。

下面再來(lái)看看如果hlist_node中包含兩個(gè)分別指向前驅(qū)結(jié)點(diǎn)和后繼結(jié)點(diǎn)的指針

很明顯刪除hash桶對(duì)應(yīng)鏈表中的非第一個(gè)普通結(jié)點(diǎn),只需要如下兩行代碼:

n->next->prev = n->prev;
n->prev->next = n->next;
可是,如果是刪除的hash桶對(duì)應(yīng)鏈表中的第一個(gè)普通結(jié)點(diǎn):
此時(shí) n->prev->next = n->next 就會(huì)出問(wèn)題,因?yàn)閔ash桶的表頭結(jié)點(diǎn)沒(méi)有next域
所以,明顯在這種情況下刪除hash桶對(duì)應(yīng)鏈表的第一個(gè)普通結(jié)點(diǎn)和非第一個(gè)普通結(jié)點(diǎn)的代碼是不一樣的。
同樣的情況也存在于插入操作。

附一張?jiān)趆ash桶頭結(jié)點(diǎn)之后,插入第一個(gè)普通結(jié)點(diǎn)的圖:


在遍歷上,如果使用hlist_hode, list_node指針進(jìn)行遍歷,兩者過(guò)程大致相似。

#define list_for_each(pos, head)
        for (pos = (head)->next; prefetch(pos->next), pos != (head);
                pos = pos->next)

#define hlist_for_each(pos, head)
        for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; });
             pos = pos->next)
如果使用其寄生結(jié)構(gòu)的指針進(jìn)行遍歷,則hlistlist也略有不同,hlist在遍歷時(shí)需要一個(gè)指向hlist_node的臨時(shí)指針,該指針的引入,一是為了遍歷,而list的遍歷在list_entry的參數(shù)中實(shí)現(xiàn)了,更主要的目的在于判斷結(jié)束,因?yàn)?/span>hlist最后一個(gè)節(jié)點(diǎn)的nextNULL,只有hlist_node指向NULL時(shí)才算結(jié)束,而這個(gè)NULL不包含在任何寄生結(jié)構(gòu)內(nèi),不能通過(guò)tpos->member的方式訪問(wèn)到,故臨時(shí)變量pos的引入時(shí)必須的。

#define list_for_each_entry(pos, head, member)
        for (pos = list_entry((head)->next, typeof(*pos), member);
             prefetch(pos->member.next), &pos->member != (head);
             pos = list_entry(pos->member.next, typeof(*pos), member))
 
#define hlist_for_each_entry(tpos, pos, head, member)
        for (pos = (head)->first;
             pos && ({ prefetch(pos->next); 1;}) &&
                ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
             pos = pos->next)
另外,listhlist的遍歷都實(shí)現(xiàn)了safe版本,因在遍歷時(shí),沒(méi)有任何特別的東西來(lái)阻止對(duì)鏈表執(zhí)行刪除操作(通常在使用鏈表時(shí)使用鎖來(lái)保護(hù)并發(fā)訪問(wèn))。安全版本的遍歷函數(shù)使用臨時(shí)存放的方法使得檢索鏈表時(shí)能不被刪除操作所影響。

#define list_for_each_safe(pos, n, head)
        for (pos = (head)->next, n = pos->next; pos != (head);
                pos = n, n = pos->next)
 
#define hlist_for_each_safe(pos, n, head)
        for (pos = (head)->first; pos && ({ n = pos->next; 1; });
             pos = n)
附上linux內(nèi)核中與hlist相關(guān)的完整代碼:

//hash桶的頭結(jié)點(diǎn)
struct hlist_head {
     struct hlist_node *first; //指向每一個(gè)hash桶的第一個(gè)結(jié)點(diǎn)的指針
};
//hash桶的普通結(jié)點(diǎn)
struct hlist_node {
 struct hlist_node *next; //指向下一個(gè)結(jié)點(diǎn)的指針
 struct hlist_node **pprev; //指向上一個(gè)結(jié)點(diǎn)的next指針的地址
};
//以下三種方法都是初始化hash桶的頭結(jié)點(diǎn)
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)

//初始化hash桶的普通結(jié)點(diǎn)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
 h->next = NULL;
 h->pprev = NULL;
}

//判斷一個(gè)結(jié)點(diǎn)是否已經(jīng)存在于hash桶中
static inline int hlist_unhashed(const struct hlist_node *h)
{
     return !h->pprev;
}

//判斷一個(gè)hash桶是否為空
static inline int hlist_empty(const struct hlist_head *h)
{
     return !h->first;
}

static inline void __hlist_del(struct hlist_node *n)
{
 struct hlist_node *next = n->next; //獲取指向待刪除結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)的指針
 struct hlist_node **pprev = n->pprev; //保留待刪除結(jié)點(diǎn)的pprev域
 *pprev = next; //修改待刪除結(jié)點(diǎn)的pprev域,邏輯上使待刪除結(jié)點(diǎn)的前驅(qū)結(jié)點(diǎn)指向待刪除結(jié)點(diǎn)的后繼結(jié)點(diǎn)
 if (next)
  next->pprev = pprev; //設(shè)置待刪除結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)的pprev域,保持hlist的結(jié)構(gòu)
}

static inline void hlist_del(struct hlist_node *n)
{
 __hlist_del(n); //刪除結(jié)點(diǎn)之后,需要將其next域和pprev域設(shè)置為無(wú)用值
 n->next = LIST_POISON1;
 n->pprev = LIST_POISON2;
}

static inline void hlist_del_init(struct hlist_node *n)
{
 if (!hlist_unhashed(n))
 {
  __hlist_del(n);
  INIT_HLIST_NODE(n);
 }
}

//將普通結(jié)點(diǎn)n插入到頭結(jié)點(diǎn)h對(duì)應(yīng)的hash桶的第一個(gè)結(jié)點(diǎn)的位置
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
 struct hlist_node *first = h->first;
 n->next = first;
 if (first)
  first->pprev = &n->next;
 h->first = n;
 n->pprev = &h->first;
}

/* next must be != NULL */
//在next結(jié)點(diǎn)之前插入結(jié)點(diǎn)n,即使next結(jié)點(diǎn)是hash桶中的第一個(gè)結(jié)點(diǎn)也可以

static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next)
{
 n->pprev = next->pprev;
 n->next = next;
 next->pprev = &n->next;
 *(n->pprev) = n;
}

//在結(jié)點(diǎn)n之后插入結(jié)點(diǎn)next
static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next)
{
 next->next = n->next;
 n->next = next;
 next->pprev = &n->next;

 if (next->next)
  next->next->pprev = &next->next;
}

/*
 * Move a list from one list head to another. Fixup the pprev
 * reference of the first entry if it exists.
 */

static inline void hlist_move_list(struct hlist_head *old, struct hlist_head *new)
{
 new->first = old->first;
 if (new->first)
  new->first->pprev = &new->first;
 old->first = NULL;
}

//通過(guò)一個(gè)結(jié)構(gòu)體內(nèi)部一個(gè)成員的地址獲取結(jié)構(gòu)體的首地址
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)

#define hlist_for_each(pos, head)
 for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; });
      pos = pos->next)

#define hlist_for_each_safe(pos, n, head)
 for (pos = (head)->first; pos && ({ n = pos->next; 1; });
      pos = n)

/**
 * hlist_for_each_entry    - iterate over list of given type
 * @tpos:    the type * to use as a loop cursor.
 * @pos:    the &struct hlist_node to use as a loop cursor.
 * @head:    the head for your list.
 * @member:    the name of the hlist_node within the struct.
 */

#define hlist_for_each_entry(tpos, pos, head, member)    
 for (pos = (head)->first;    
      pos && ({ prefetch(pos->next); 1;}) &&    
  ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
      pos = pos->next)

/**
 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
 * @tpos:    the type * to use as a loop cursor.
 * @pos:    the &struct hlist_node to use as a loop cursor.
 * @member:    the name of the hlist_node within the struct.
 */

#define hlist_for_each_entry_continue(tpos, pos, member)    
 for (pos = (pos)->next;    
      pos && ({ prefetch(pos->next); 1;}) &&    
  ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
      pos = pos->next)

/**
 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
 * @tpos:    the type * to use as a loop cursor.
 * @pos:    the &struct hlist_node to use as a loop cursor.
 * @member:    the name of the hlist_node within the struct.
 */

#define hlist_for_each_entry_from(tpos, pos, member)    
 for (; pos && ({ prefetch(pos->next); 1;}) &&    
  ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
      pos = pos->next)

/**
 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @tpos:    the type * to use as a loop cursor.
 * @pos:    the &struct hlist_node to use as a loop cursor.
 * @n:     another &struct hlist_node to use as temporary storage
 * @head:    the head for your list.
 * @member:    the name of the hlist_node within the struct.
 */

#define hlist_for_each_entry_safe(tpos, pos, n, head, member)
 for (pos = (head)->first;    
      pos && ({ n = pos->next; 1; }) &&
  ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
      pos = n)
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
linux內(nèi)核V2.6.11學(xué)習(xí)筆記(2)--list和hlist(3)
hlist哈希鏈表
Hash Table哈希表和Hash List哈希鏈表的知識(shí)匯總
RCU
Linux 內(nèi)核進(jìn)程管理之進(jìn)程ID
紅茶一杯話Binder(傳輸機(jī)制篇
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服