Tasklet System

Tasklet

Quasi tutti i moduli che compongono il demone ntkd fanno uso di tasklet per svolgere i loro compiti. Si tratta di thread cooperativi, cioè che permettono allo schedulatore di passare l'esecuzione ad un altro thread soltanto su specifica autorizzazione da parte del thread corrente.

L'autorizzazione a schedulare altre tasklet viene data da parte della tasklet corrente con una delle seguenti modalità:

Inoltre la tasklet corrente può creare altre tasklet, attraverso la funzione spawn . Questo consiste nel dire allo schedulatore che una certa chiamata ad una funzione dovrà essere eseguita in una nuova tasklet. La nuova tasklet non verrà comunque iniziata dallo schedulatore fino a quando la tasklet corrente non lo consentirà attraverso una delle modalità dette in precedenza.

La funzione spawn restituisce un handle per la tasklet creata. Tramite questo handle è possibile verificare se la tasklet è ancora in esecuzione. Si può inoltre richiedere la terminazione della tasklet.

Alla funzione spawn si può indicare se la nuova tasklet dovrà essere joinable . In questo caso tramite il suo handle sarà possibile chiamare il metodo join : la tasklet corrente si blocca in attesa che la tasklet individuata dall'handle termini e poi riceve il valore di ritorno dell'esecuzione della tasklet; si tratta di un void * che di norma è il valore di ritorno della funzione con cui la tasklet ha avuto inizio.

La tasklet corrente può richiedere di terminare se stessa, con un eventuale valore di ritorno, indipendentemente dalla profondità di chiamate nel suo stack che ha raggiunto.

Due tasklet possono comunicare tra loro attraverso un canale . Se due tasklet condividono un canale questo fornisce loro un meccanismo per comunicare tra loro senza bloccarsi.

E' stata realizzata una libreria che contiene alcune interfacce di programmazione verso un generico sistema di tasklet. Si chiama tasklet-system.

Questa libreria sarà una dipendenza nel pacchetto software di ogni singolo modulo. Ma tali pacchetti non saranno tenuti ad avere una dipendenza sulla specifica libreria che implementa il sistema di tasklet.

La libreria tasklet-system sarà una dipendenza anche nel pacchetto software che raccoglie i vari moduli e produce l'eseguibile del demone ntkd. Il compito di tale pacchetto sarà quello di fornire ai vari moduli una implementazione delle interfacce del sistema di tasklet, quindi avrà una dipendenza anche sulla specifica libreria che usa a tale scopo.

Si cerca così di rendere i vari moduli del demone ntkd indipendenti dalla implementazione delle tasklet. La prima implementazione che useremo nel demone sarà la libreria PthTasklet basata su GNU/Pth, ma dovrebbe essere possibile usare altre implementazioni.

Interfacce

L'interfaccia ITasklet prevede questi metodi:

L'interfaccia ITaskletSpawnable prevede questi metodi:

L'interfaccia ITaskletHandle prevede questi metodi:

La classe TaskletCommandResult ha questi membri:

L'interfaccia IServerStreamSocket si usa lato server. Essa prevede questi metodi:

L'interfaccia IConnectedStreamSocket si usa su entrambi gli end point della connessione. Essa prevede questi metodi:

L'interfaccia IServerDatagramSocket prevede questi metodi:

L'interfaccia IClientDatagramSocket prevede questi metodi:

L'interfaccia IChannel prevede questi metodi:

Quando si desidera avviare una tasklet occorre creare appositamente una istanza di una classe che implementa l'interfaccia ITaskletSpawnable. Tale classe ha come membri tutti i dati che andrebbero passati alla funzione che inizia il task. Inoltre ha il metodo func che è proprio quello che costituisce il corpo della tasklet che si vuole avviare. La classe che si istanzia può essere interna ad un'altra classe per fare in modo che abbia accesso ai suoi membri privati.

Poi si valorizzano i membri della istanza di ITaskletSpawnable, come sarebbero passati gli argomenti alla funzione. Quindi si chiama il metodo spawn di ITasklet, al quale si può indicare se si desidera che la nuova tasklet sia joinable.

L'istanza di ITaskletHandle restituita dal metodo spawn potrà essere usata per fare il join della tasklet (se è joinable) oppure in caso di necessità per abortirla.

Quando il metodo spawn restituisce il controllo al chiamante, esso è tenuto a rimuovere immediatamente il suo riferimento alla istanza di ITaskletSpawnable.

Il metodo spawn si occupa di memorizzare un riferimento all'istanza di ITaskletSpawnable per evitare che venga distrutta e di mantenerlo in vita fino alla fine della tasklet che andiamo a creare. Poi il metodo crea la nuova tasklet, che eseguirà un'apposita funzione che chiamiamo real_func , con l'implementazione che si intende adottare, sia essa PthTasklet (basata su GNU/Pth) o similari. Di norma la funzione real_func ha in C la signature "void *(*)(void *)". Come argomento viene passata l'istanza di ITaskletSpawnable dopo averne fatto il cast a (void *).

Nella nuova tasklet, la funzione real_func riceve il dato come (void *) e ne fa il cast a (ITaskletSpawnable *). Poi richiama il suo metodo func e memorizza il suo valore di ritorno. Infine rimuove il riferimento all'istanza di ITaskletSpawnable e poi termina restituendo il valore di ritorno di func .

Tasklet sequenziali

La libreria tasklet-system fornisce anche un metodo per assicurare che alcune tasklet vengano eseguite in sequenza. Usiamo un esempio per illustrare cosa si intende con questa espressione.

Sia un evento e che quando si verifica avvia una lunga elaborazione. All'inizio di questa elaborazione viene scritto a video il messaggio "elaborazione avviata" con un timestamp. Al termine della elaborazione viene scritto a video il messaggio "elaborazione terminata" con un timestamp. Supponiamo ora che questo evento e possa essere segnalato da due tasklet t1 e t2 che sono eseguite parallelemante. Può quindi avvenire che la tasklet t1 segnala l'evento e e mentre l'elaborazione è in corso, la tasklet t2 segnala anch'essa l'evento e. Noi però, per qualche motivo, vogliamo che non si accavallino a video i messaggi di inizio e fine elaborazione; vogliamo che il messaggio di "elaborazione terminata" con il relativo timestamp sia sempre riferibile al messaggio di "elaborazione avviata" che subito lo precede.

Con il meccanismo che fornisce la libreria tasklet-system l'applicazione crea una istanza di DispatchableTasklet e la memorizza in una variabile dt. Inoltre, l'elaborazione da fare come risposta all'evento e viene scritta come una tasklet, cioè nel metodo "func" di una classe che implementa ITaskletSpawnable. Quando si verifica l'evento e viene creata una istanza ts di questa classe e valorizzati i suoi membri come per passare gli argomenti alla funzione "func"; poi viene chiamato su dt il metodo dispatch passando l'istanza st.

La libreria farà in modo che l'elaborazione avviata dalla tasklet t1 venga completata prima di iniziare l'elaborazione avviata dalla tasklet t2.

Questo meccanismo viene fornito dalla libreria tasklet-system, quindi il suo utilizzatore non lo deve implementare. Per fornirlo, la libreria si avvale delle implementazioni di tasklet e canali di cui si è parlato prima, le quali invece sono proprio implementate dall'utilizzatore.

L'interfaccia ITasklet fornisce quindi questo ulteriore metodo, non astratto:

La classe DispatchableTasklet fornisce questi metodi:

Inizializzazione

I moduli del demone ntkd che fanno uso delle tasklet vengono "inizializzati" con alcune chiamate, fra cui il metodo init_tasklet_system . In esso il modulo principale fornisce le implementazioni delle interfacce usate per le comunicazioni allo schedulatore.

Praticamente deve fornire una istanza di ITasklet.

Netsukuku/ita/docs/Librerie/TaskletSystem (last edited 2017-01-17 13:34:39 by lukisi)