2013-04-26 24 views
16

誰もLinuxのlist_for_each_entryとentry_safeループの作業を説明することはできますか? それはすべてのこれらのパラメータの役割とそれらがどのようにリストをトラバースするために使用されているが、どのようなものがあり説明list_for_each_entryとlist_for_each_entry_safe

list_for_each_entry(type *cursor, struct list_head *list, member)

list_for_each_entry_safe(type *cursor, type *next, struct list_head *list,member)

のようなものです。事前に

おかげ

+1

私はあなたがLinuxカーネルを理解する本を読むことをお勧め。 – stdcall

+0

あなたの提案をお寄せいただきありがとうございます。 – goodies

答えて

12

EDIT:申し訳ありませんが、それは遅く、私はタイプミスをたくさん作りましたしなければなりません。

彼らは純粋な楽しみです! :)違いは、list_for_each_entryは、リストを反復している間に何かを削除し、list_for_each_entry_safeが(もちろん余分なCPU命令を犠牲にして)削除されないということです。

カーネルはlist.hの中でリンクされたリストの実装がありますが、二重リンクされたリスト(あなたが理解していると思います)で解決しました。あなたのリストはちょうどです:

リストの "ヘッド"と各ノードの両方に同じ構造体が使用されています。リストが空の場合、頭部のnextprevのメンバーは、自分自身の頭を指しているだけです。したがって、リストを反復することは、頭部のnextメンバーから始め、prev(停止時)と同じアドレスでない限り、そのノードを呼び出すプロセスに過ぎません。それ以外の場合は、for本体が呼び出され、container_of()マクロを使用して実際の構造体へのポインタを取得し、それを使用して再生することができます。その後、forの3番目のフィールドでは、次のnextに移動します。

EDIT:whoops、私はお詫び申し上げます。パラメータの説明を求めました。さて、もしあなたが誰かの言葉を取るよりもむしろ私は直接それを調べるでしょう。そのためには、少なくともリンクリストライブラリのために存在するKernel API docs自身をお勧めします。私は、赤黒のツリーライブラリのためにそれらを追加するパッチセットを取得しようとしていますが、物事を得ることはかなりのプロセスになる可能性があります。ノートのも

http://kernelnewbies.org/FAQ/LinkedLists

は、ここでは簡単な例です:

struct list_head my_actual_list; 
struct my_struct { 
    struct list_head node; 
    /* some other members */ 
}; 

/* in a function body somewhere... */ 
struct list_head *i; 
list_for_each(i, &my_actual_list) { 
    struct my_struct *obj = list_entry(i, struct my_struct, node); 
    // do something with obj 
} 

list_entryは答えではので、container_of

EDIT#2

OKためだけの別名でありますコメントであなたの質問に、私は私の答えを拡大するつもりです。 C++ STLコンテナ、C配列などと比べると、奇妙なことがいくつかありますが、この概念を理解するのが難しいのは分かりますが、いったんこの熟語に慣れれば、それはかなり自然に見えます。今後も、これらの構造体、関数&マクロの定義を見て、理解を深めてから質問してみることをお勧めします。

だから、最初のオフは、あなたのリスト内の各ノードは、タイプstruct list_headのメンバーと自己はタイプstruct list_headのあるリストが含まれています構造体です。したがって、コンテナは誰であり、このケースに含まれているかは、単にそれらがどのように使用されているかに依存するが、典型的には、これらのメンバーが与えられた名前で表される。イテレータのタイプはstruct list_head *です。ここでは一例だと、私は彼らの同等のコードを通常の関数&マクロ呼び出しを置き換えます:

struct my_container { 
    struct list_head list; 
    int some_member; 
    /* etc. */ 
}; 

struct my_obj { 
    struct list_head node; 
    int some_member; 
    /* etc. */ 
}; 

void func() { 
    struct my_container container; 
    struct my_obj obj1, obj2; 
    struct list_head *i; 

    /* INIT_LIST_HEAD(&container.list); */ 
    container.list.next = &container.list; 
    container.list.prev = &container.list; 

    /* list_add_tail(&obj1.node); */ 
    container.list.prev = &obj1.node; 
    obj1.node.next = &container.list; 
    obj1.node.prev = &container.list; 
    container.list.next = &obj1.node; 

    /* list_add_tail(&obj2.node); */ 
    container.list.prev = &obj2.node; 
    obj2.node.next = &container.list; 
    obj2.node.prev = &obj1.node; 
    obj1.node.next = &obj2.node; 

    /* list_for_each(i, &container.list) { */ 
    for (i = container.list.next; i != &container.list; i = i->next) { 
     struct my_obj *obj = list_entry(i, struct my_obj, node); 
     /* do stuff */ 
    } 

} 

Now go read! :)

+0

私はあなたにお付き合いしていますが、どのように関係しているか、このイテレータがチェックする条件を知りたいと思います。 (int i = 0; i <= 5; i ++)** このイテレータはどのようにして次の要素をチェックするかを次のように繰り返します。 – goodies

+1

ああ、変数名私はイテレーターと呼んでいるので、「私」です。変数名 'pos'を使う人もいますが、これはリスト内の「位置」ですが、私は「イテレータ」規約に従うことを好みます。これは長いので、私は答えを広げるつもりです。 –