Upload
marc-lamotte
View
113
Download
3
Embed Size (px)
Citation preview
Liste générique dans Linux 2.6Liste générique dans Linux 2.6
Source : Understanding the Linux kernel Chap3 processes p.87
planplan
Pointeur
Structure
Chaînage
Liste
Les pointeursLes pointeurs
Gestion de l’espace méémoire en cours d’exéécution
Modifications de variables passéées en paramèètres de fonction
Repréésentation de tableaux: accèès direct et indexéé
int* a;
Déclaration d’un pointeur vers un entier et initialisation à “NULL”
int* a = NULL;
a
Rappels sur les pointeursRappels 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
RappelsRappels
#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
00000000
00000000
pk=0x33c18
pk+1=0x33c1c
00000000
00000000
00001010
00000000
00000000
00010100
10
20
Rappels : les structuresRappels : 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 nom 00x3 prenom 1
0x10 age 8
RappelsRappels
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 l’index i.
RappelsRappels
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 intLa 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 pointeursRappels: 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== nomadressenomadresse.Num ou (*ptr).num désigne une variable de type int Les parenthèses sont nécessaires car l’opérateur point. Qui donne l’accès aux champs d’une structure est prioritaire sur *
On désignera volontiers (*ptr).num par ptr->num
Rappel : erreur couranteRappel : 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 l’exé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ù l’on puisse stocker la structure ; elle ne réserve pas la place d’une structure à l’adresse pointée par ptr.
il faut soit : •ptr=&nomadresse; ou
•ptr = malloc(sizeof(*ptr));
Rappel : listeRappel : 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 ?Double liste chaînée ?
La liste est doublement chaînée.Elle ne contient aucune donnée à l’intérieur ?prev
next
list _head
Déclaration 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înageChaî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 _headprev
next
list _head
ChaînageChaînage
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
new
prev next
ChaînageChaînage
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
new
prev next
next->prev = new;new->next = next;new->prev = prev;prev->next = new;
ChaînageChaînage
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
new
prev next
next->prev = new;
new->next = next;new->prev = prev;prev->next = new;
ChaînageChaînage
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
new
prev next
next->prev = new;new->next = next;
new->prev = prev;prev->next = new;
ChaînageChaînage
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
new
prev next
next->prev = new;new->next = next;new->prev = prev;
prev->next = new;
ChaînageChaînage
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
prev next
next->prev = new;new->next = next;new->prev = prev;prev->next = new;
Fin d’insertion connaissant Prev et NextFin d’insertion connaissant Prev et Next
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
prev
next
list _head
prev
next
list _headprev
next
list _head Avant
Après
Insertion en têteInsertion en tête
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
new
Insertion en queue Insertion en queue
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
new
Autres fonctionsAutres fonctions
•List_empty•List_delete
MacrosMacros
/** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \ pos = pos->next)
planplan
Pointeur
Structure
Chaînage
Liste
Manipulation des listesManipulation des listes
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
Struc1 Struc2 Struc3
Et pas un pointage sur la tête de la structureEt pas un pointage sur la tête de la structure
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
Struc1 Struc2 Struc3
Manipulation des listesManipulation des listes
prev
next
list _head
prev
next
list _headprev
next
list étudiants
prev
next
list _head
Struc1 Struc2 Struc3
prev
next
list _head
prev
next
list _headprev
next
list alternants
Manipulation des listesManipulation des listes
prev
next
list _head
prev
next
list _headprev
next
list _head
prev
next
list _head
Struc1 Struc2 Struc3
Mais comment récupérer ces pointeurs ?
RappelsRappels
struct humain { char nom[1]; char prenom[4]; int age; };
0x2 nom0x3 prenom
0x10 age
Containerof.c
Offsetof : Offsetof :
offsetof(struct nomprenomage,age))= &((struct nomprenomage *)0)->age 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
RappelsRappels
struct humain { char nom[1]; char prenom[4]; int age; };
0x2 nom 00x3 prenom 1
0x10 age 8
Containerof.c
offsetof
Comment obtenir la valeur du pointeur sur la structComment obtenir la valeur du pointeur sur la struct
struct humain { char nom[1]; char prenom[4]; int age; };
0x2 nom0x3 prenom
0x10 ageConnu
Containerof.c
?
Container_ofContainer_of
#define container_of(ptr, type, member) ({\
const typeof( ((type *)0)->member ) *__mptr = (ptr);\
(type *)( (char *)__mptr - offsetof(type,member) );})
Pour avoir l’adresse du début de la structure connaissant l’adresse d’un des membres :
ptr = container_of(ptrhumain ->age,struct humain,age);
Include/linux/kernel.h
List_entry(p,t,m)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 * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the 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ériquePourquoi une liste générique
Le noyau a besoin de conserver beaucoup d’informations
La liste de tous les processus
La liste des processus actifs
La liste des processus actifs suspendus
A compléter
Pour éviter d’implé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 processusExemple 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_entryMacro list_for_each_entry
/** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the 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 listesManipulation des listes
prev
nextlist_head
prev
nextlist_head
prev
nextétudiants
prev
nextlist_head
Struc1 Struc2 Struc3
prev
nextlist_head
prev
nextlist_head
prev
nextalternants
0x33c0offset=0
0x33c8offset=8
0x33cfoffset=f
RappelsRappels
struct humain { char nom[1]; char prenom[4]; int age; };
offsetof(struct humain,age));= 8
0xff2 nom 00xff3 prenom 1
0xffA age 8
adresse offsetof