Per organizzare i dati come lista collegata usando struct list_head
devi dichiarare list root e dichiarare la voce dell'elenco per il collegamento. Entrambe le voci radice e figlio sono dello stesso tipo (struct list_head
). children
voce di struct task_struct
la voce è un root
. sibling
voce di struct task_struct
è un list entry
. Per vedere le differenze, devi leggere il codice, dove children
e sibling
sono usati. Utilizzo di list_for_each
per children
significa cosa children
è un root
. Utilizzo di list_entry
per sibling
significa cosa sibling
è un list entry
.
Puoi leggere di più sugli elenchi dei kernel Linux qui.
Domanda :Qual è il motivo per cui stiamo passando "sibling" qui che alla fine un elenco diverso con offset diverso?
Risposta:
Se l'elenco è stato creato in questo modo:
list_add(&subtask->sibling, ¤t->children);
Di
list_for_each(list, ¤t->children)
Inizializzerà i puntatori di elenco a sibling
, quindi devi usare subling
come parametro per list_entry. Ecco come il kernel Linux elenca le API progettate.
Ma, se l'elenco è stato creato in un altro (errato ) modo:
list_add(&subtask->children, ¤t->sibling);
Quindi devi iterare l'elenco in questo modo (sbagliato ) modo:
list_for_each(list, ¤t->sibling)
E ora devi usare children
come parametro per list_entry
.
Spero, questo aiuta.
Di seguito la rappresentazione pittorica che potrebbe aiutare qualcuno in futuro. La casella in alto rappresenta un genitore, e le due caselle in basso sono i suoi figli
Ecco un'immagine in aggiunta alle risposte precedenti. Lo stesso processo può essere sia genitore che figlio (come Genitore1 nell'immagine) e dobbiamo distinguere tra questi due ruoli.
Intuitivamente, se children
di Parent0 punterebbe a children
di Parent1, quindi Parent0.children.next->next
(cerchio verde sull'immagine), che è lo stesso di Parent1.children.next
, indicherebbe un figlio di Parent1 invece di un figlio successivo di Parent0.