Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87
plan Pointeur Structure Chaînage Liste
Les pointeurs éé Gestion de lespace mémoire en cours dexécution éè Modifications de variables passées en paramètres de fonction éèé Représentation de tableaux: accès direct et indexé
int* a; Déclaration dun pointeur vers un entier et initialisation à NULL int* a = NULL; a Rappels sur les pointeurs
int* a = malloc(3*sizeof(int)); Allocation dynamique et assignement int* a = (int*)malloc(3*sizeof(int)); a *a
Désallocation dynamique free(a); a a = NULL; *a
Rappels #define NB_ELEMENTS 2 int *pk; pk = malloc(NB_ELEMENTS * sizeof(int)); //allocation pour 2 int *pk = 10; *(pk + 1) = 20; #define NB_ELEMENTS 2 int *pk; pk = malloc(NB_ELEMENTS * sizeof(int)); //allocation pour 2 int *pk = 10; *(pk + 1) = 20; Malloc.c pk=0x33c18 pk+1=0x33c1c
Rappels : les structures struct nomprenomage { char nom[1]; char prenom[4]; int age; }; Struct nomprenomage * ptr; ptr = &nomprenomage; ptr->age ~ (*ptr).nom struct nomprenomage { char nom[1]; char prenom[4]; int age; }; Struct nomprenomage * ptr; ptr = &nomprenomage; ptr->age ~ (*ptr).nom 0x2 nom0 0x3 prenom1 0x10 age8
Rappels struct nomprenomage { char nom[10]; char prenom[10]; int age; }; Struct nomprenomage groupe[n]; struct nomprenomage { char nom[10]; char prenom[10]; int age; }; Struct nomprenomage groupe[n]; groupe[i].nom référence le nom de la personne qui a lindex i.
Rappels struct adresse { char *rue; int num; } nomadresse; struct adresse { char *rue; int num; } nomadresse; Cette définition réserve en mémoire la place pour 2 variables : La variable nomadresse.num de type int La variable nomadresse.rue de type pointeur sur le type char Cette définition ne réserve pas de place pour stocker le nom de rue.
Rappels: structures et pointeurs struct adresse { char *rue; int num; } nomadresse; struct adresse nomadresse *ptr; ptr=&nomadresse; struct adresse { char *rue; int num; } nomadresse; struct adresse nomadresse *ptr; ptr=&nomadresse; On a donc *ptr== nomadresse nomadresse.Num ou (*ptr).num désigne une variable de type int Les parenthèses sont nécessaires car lopérateur point. Qui donne laccès aux champs dune structure est prioritaire sur * On désignera volontiers (*ptr).num par ptr->num
Rappel : erreur courante struct adresse { char *rue; int num; }; struct adresse nomadresse *ptr; … ptr->num=12 struct adresse { char *rue; int num; }; struct adresse nomadresse *ptr; … ptr->num=12 A lexécution tout peut arrivé ! struct adresse nomadresse *ptr; réserve la place pour stoquer une adresse mais ne garantie pas que la valeur de p est une adresse où lon puisse stocker la structure ; elle ne réserve pas la place dune structure à ladresse pointée par ptr. il faut soit : ptr=&nomadresse; ou ptr = malloc(sizeof(*ptr));
Rappel : liste struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) include/linux/list.h
Double liste chaînée ? La liste est doublement chaînée. Elle ne contient aucune donnée à lintérieur ? prev next list_head
Déclaration exemple de déclaration linux/kernel/timer.c dans static inline void __run_timers(tvec_base_t *base) struct list_head work_list = LIST_HEAD_INIT(work_list); struct list_head *head = &work_list;
Chaînage List_head est le premier élément vide qui joue un rôle particulier de placeholder pour la tête de la nouvelle liste prev next list_head prev next list_head prev next list_head
Chaînage prev next list_head prev next list_head prev next list_head prev next list_head new prevnext
Chaînage prev next list_head prev next list_head prev next list_head prev next list_head new prevnext next->prev = new; new->next = next; new->prev = prev; prev->next = new;
Chaînage prev next list_head prev next list_head prev next list_head prev next list_head new prevnext next->prev = new; new->next = next; new->prev = prev; prev->next = new;
Chaînage prev next list_head prev next list_head prev next list_head prev next list_head new prevnext next->prev = new; new->next = next; new->prev = prev; prev->next = new;
Chaînage prev next list_head prev next list_head prev next list_head prev next list_head new prevnext next->prev = new; new->next = next; new->prev = prev; prev->next = new;
Chaînage prev next list_head prev next list_head prev next list_head prev next list_head prevnext next->prev = new; new->next = next; new->prev = prev; prev->next = new;
Fin dinsertion connaissant Prev et Next prev next list_head prev next list_head prev next list_head prev next list_head prev next list_head prev next list_head prev next list_head Avant Après
Insertion en tête prev next list_head prev next list_head prev next list_head prev next list_head new
Insertion en queue prev next list_head prev next list_head prev next list_head prev next list_head new
Autres fonctions List_empty List_delete
Macros /** * list_for_each-iterate over a list &struct list_head to use as a loop counter. head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; prefetch(pos->next), pos != (head); \ pos = pos->next)
plan Pointeur Structure Chaînage Liste
Manipulation des listes prev next list_head prev next list_head prev next list_head prev next list_head Struc1Struc2Struc3
Et pas un pointage sur la tête de la structure prev next list_head prev next list_head prev next list_head prev next list_head Struc1Struc2Struc3
Manipulation des listes prev next list_head prev next list_head prev next listétudiants prev next list_head Struc1Struc2Struc3 prev next list_head prev next list_head prev next listalternants
Manipulation des listes prev next list_head prev next list_head prev next list_head prev next list_head Struc1Struc2Struc3 Mais comment récupérer ces pointeurs ?
Rappels struct humain { char nom[1]; char prenom[4]; int age; }; 0x2 nom 0x3 prenom 0x10 age Containerof.c
Offsetof : offsetof(struct nomprenomage,age))= &((struct nomprenomage *)0)->age Or (struct nomprenomage *)0 définit un pointeur de valeur 0 offsetof(struct nomprenomage,age)= (struct nomprenomage *)0 – &((struct nomprenomage *)0)->age Linux/stdef.h
Rappels struct humain { char nom[1]; char prenom[4]; int age; }; 0x2 nom0 0x3 prenom1 0x10 age8 Containerof.c offsetof
Comment obtenir la valeur du pointeur sur la struct struct humain { char nom[1]; char prenom[4]; int age; }; 0x2 nom 0x3 prenom 0x10 age Connu Containerof.c ?
Container_of #define container_of(ptr, type, member) ({\ const typeof( ((type *)0)->member ) *__mptr = (ptr);\ (type *)( (char *)__mptr - offsetof(type,member) );}) Pour avoir ladresse du début de la structure connaissant ladresse dun des membres : ptr = container_of(ptrhumain ->age,struct humain,age); Include/linux/kernel.h
List_entry(p,t,m) #define list_entry(ptr, type, member) container_of(ptr, type, member) /** * container_of - cast a member of a structure out to the containing structure pointer to the member. type of the container struct this is embedded in. name of the member within the struct. * */ #define container_of(ptr, type, member) ({\ const typeof( ((type *)0)->member ) *__mptr = (ptr);\ (type *)( (char *)__mptr - offsetof(type,member) );})
Pourquoi une liste générique Le noyau a besoin de conserver beaucoup dinformations La liste de tous les processus La liste des processus actifs La liste des processus actifs suspendus A compléter Pour éviter dimplémenter pour chaque type de liste les primitives de bases et pour un gain de mémoire, il est intéressant de définir une structure de liste générique.
Exemple avec les processus Include/linux/sched.h struct task_struct { … struct list_head run_list; … struct list_head tasks; … struct list_head ptrace_children; struct list_head ptrace_list; … struct list_head children;/* list of my children */ struct list_head sibling;/* linkage in my parent's children list */ … struct list_head cpu_timers[3]; };
Macro list_for_each_entry /** * list_for_each_entry-iterate over list of given type type * to use as a loop counter. head for your list. name of the list_struct within the struct. */ #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)) Permet de pointer sur chaque éléments de la liste :
Manipulation des listes prev next list _head prev next list _head prev next étudiants prev next list_head Struc1Struc2Struc3 prev next list_head prev next list_head prev next alternants 0x33c0 offset=0 0x33c8 offset=8 0x33cf offset=f
Rappels struct humain { char nom[1]; char prenom[4]; int age; }; offsetof(struct humain,age)); = 8 0xff2 nom0 0xff3 prenom1 0xffA age8 adresse offsetof