44
Liste générique dans Linux 2.6 Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

Embed Size (px)

Citation preview

Page 1: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

Liste générique dans Linux 2.6Liste générique dans Linux 2.6

Source : Understanding the Linux kernel Chap3 processes p.87

Page 2: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

planplan

Pointeur

Structure

Chaînage

Liste

Page 3: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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éé

Page 4: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

int* a;

Déclaration d’un pointeur vers un entier et initialisation à “NULL”

int* a = NULL;

a

Rappels sur les pointeursRappels sur les pointeurs

Page 5: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87
Page 6: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

int* a = malloc(3*sizeof(int));

Allocation dynamique et assignement

int* a = (int*)malloc(3*sizeof(int));

a *a

Page 7: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

Désallocation dynamique

free(a);

a

a = NULL;

*a

Page 8: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 9: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 10: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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.

Page 11: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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.

Page 12: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 13: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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));

Page 14: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 15: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 16: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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;

Page 17: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 18: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

ChaînageChaînage

prev

next

list _head

prev

next

list _headprev

next

list _head

prev

next

list _head

new

prev next

Page 19: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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;

Page 20: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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;

Page 21: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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;

Page 22: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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;

Page 23: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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;

Page 24: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 25: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

Insertion en têteInsertion en tête

prev

next

list _head

prev

next

list _headprev

next

list _head

prev

next

list _head

new

Page 26: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

Insertion en queue Insertion en queue

prev

next

list _head

prev

next

list _headprev

next

list _head

prev

next

list _head

new

Page 27: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

Autres fonctionsAutres fonctions

•List_empty•List_delete

Page 28: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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)

Page 29: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

planplan

Pointeur

Structure

Chaînage

Liste

Page 30: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

Manipulation des listesManipulation des listes

prev

next

list _head

prev

next

list _headprev

next

list _head

prev

next

list _head

Struc1 Struc2 Struc3

Page 31: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 32: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 33: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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 ?

Page 34: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

RappelsRappels

struct humain { char nom[1]; char prenom[4]; int age; };

0x2 nom0x3 prenom

0x10 age

Containerof.c

Page 35: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 36: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

RappelsRappels

struct humain { char nom[1]; char prenom[4]; int age; };

0x2 nom 00x3 prenom 1

0x10 age 8

Containerof.c

offsetof

Page 37: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

?

Page 38: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 39: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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) );})

Page 40: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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.

Page 41: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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];

};

Page 42: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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 :

Page 43: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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

Page 44: Liste générique dans Linux 2.6 Source : Understanding the Linux kernel Chap3 processes p.87

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