<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <HEAD> <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9"> <TITLE>KernelAnalysis-HOWTO: Funzioni di comune utilizzo</TITLE> <LINK HREF="KernelAnalysis-HOWTO-14.html" REL=next> <LINK HREF="KernelAnalysis-HOWTO-12.html" REL=previous> <LINK HREF="KernelAnalysis-HOWTO.html#toc13" REL=contents> </HEAD> <BODY> <A HREF="KernelAnalysis-HOWTO-14.html">Next</A> <A HREF="KernelAnalysis-HOWTO-12.html">Previous</A> <A HREF="KernelAnalysis-HOWTO.html#toc13">Contents</A> <HR> <H2><A NAME="s13">13. Funzioni di comune utilizzo</A></H2> <H2><A NAME="ss13.1">13.1 list_entry [include/linux/list.h]</A> </H2> <P>Definizione <P> <P> <PRE> #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) </PRE> <P>Significato: <P> <P>La macro "list_entry" viene usata per ricavare il puntatore ad una struttura utilizzando soltanto un elemento interno alla struttura. <P> <P>Esempio <P> <P> <PRE> struct __wait_queue { unsigned int flags; struct task_struct * task; struct list_head task_list; }; struct list_head { struct list_head *next, *prev; }; // e con la definizione del tipo: typedef struct __wait_queue wait_queue_t; // avremo: wait_queue_t *out list_entry(tmp, wait_queue_t, task_list); // dove tmp punta a list_head </PRE> <P>Quindi, in questo caso, usando il puntatore *tmp [list_head] troviamo il puntatore *out [wait_queue_t]. <P> <P> <PRE> ____________ <---- *out [abbiamo calcolato questo] |flags | /|\ |task *--> | | |task_list |<---- list_entry | prev * -->| | | | next * -->| | | |____________| ----- *tmp [partendo da questo] </PRE> <H2><A NAME="ss13.2">13.2 Sleep </A> </H2> <H3>Codice di Sleep</H3> <P>Files: <P> <P> <UL> <LI>kernel/sched.c</LI> <LI>include/linux/sched.h</LI> <LI>include/linux/wait.h</LI> <LI>include/linux/list.h </LI> </UL> <P>Funzioni: <P> <P> <UL> <LI>interruptible_sleep_on</LI> <LI>interruptible_sleep_on_timeout</LI> <LI>sleep_on</LI> <LI>sleep_on_timeout </LI> </UL> <P>Funzioni chiamate: <P> <P> <UL> <LI>init_waitqueue_entry</LI> <LI>__add_wait_queue</LI> <LI>list_add</LI> <LI>__list_add</LI> <LI>__remove_wait_queue </LI> </UL> <P>InterCallings Analysis: <P> <P> <PRE> |sleep_on |init_waitqueue_entry -- |__add_wait_queue | Accodamento della richiesta sulla lista della risorsa |list_add | |__list_add -- |schedule --- Attesa che la richiesta venga eseguita |__remove_wait_queue -- |list_del | Disaccodamento richiesta dalla lista della risorsa |__list_del -- </PRE> <P>Descrizione: <P> <P>Ogni risorsa (in teoria ogni oggetto condiviso tra piu' utenti e piu' processi), ha una cosa per gestire TUTTI i Tasks che la richiedono. <P> <P>Questo metodo di accodamento viene chiamato "wait queue" e consiste di molti elementi chiamati"wait queue element": <P> <P> <PRE> *** struttura wait queue [include/linux/wait.h] *** struct __wait_queue { unsigned int flags; struct task_struct * task; struct list_head task_list; } struct list_head { struct list_head *next, *prev; }; </PRE> <P>Rappresentazione grafica: <P> <P> <PRE> *** elemento wait queue *** /|\ | <--[prev *, flags, task *, next *]--> *** Lista wait queue *** /|\ /|\ /|\ /|\ | | | | --> <--[task1]--> <--[task2]--> <--[task3]--> .... <--[taskN]--> <-- | | |__________________________________________________________________| *** Testa wait queue *** task1 <--[prev *, lock, next *]--> taskN </PRE> <P>La Testa "wait queue" punta al primo (con next *) e last (com prev *) all'ultimo della lista "wait queue". <P> <P>Quando deve venire inserito un nuovo elemento viene chiamata la "__add_wait_queue" [include/linux/wait.h], dopo di che verra' eseguita la generica routine "list_add" [include/linux/wait.h]: <P> <P> <PRE> *** funzione list_add [include/linux/list.h] *** // classico inserimento doppio linkato static __inline__ void __list_add (struct list_head * new, \ struct list_head * prev, \ struct list_head * next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } </PRE> <P>Per completare la descrizione vediamo anche la "__list_del" [include/linux/list.h] chiamata da "list_del" [include/linux/list.h] all'interno di "remove_wait_queue" [include/linux/wait.h]: <P> <P> <PRE> *** funzione list_del [include/linux/list.h] *** // classica cancellazione doppio linkato static __inline__ void __list_del (struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } </PRE> <H3>Considerazioni sullo Stack</H3> <P>Una lista tipica (o coda) viene normalmente gestita allocandola nello Heap (si veda il Cap.10 per definizioni e gestione delle variabili nello Heap e nello Stack). <P> <P>Qui invece, allochiamo ''Wait Queue'' in una variabile locale (quindi nello Stack), dopo di che la funzione viene interrotta dalla schedulazione e, al risveglio, la variabile locale verra' cancellata <P> <P> <PRE> new task <----| task1 <------| task2 <------| | | | | | | |..........| | |..........| | |..........| | |wait.flags| | |wait.flags| | |wait.flags| | |wait.task_|____| |wait.task_|____| |wait.task_|____| |wait.prev |--> |wait.prev |--> |wait.prev |--> |wait.next |--> |wait.next |--> |wait.next |--> |.. | |.. | |.. | |schedule()| |schedule()| |schedule()| |..........| |..........| |..........| |__________| |__________| |__________| Stack Stack Stack </PRE> <HR> <A HREF="KernelAnalysis-HOWTO-14.html">Next</A> <A HREF="KernelAnalysis-HOWTO-12.html">Previous</A> <A HREF="KernelAnalysis-HOWTO.html#toc13">Contents</A> </BODY> </HTML>