Avanti Indietro Indice

4. Scrivere programmi per RTLinux

4.1 Introduzione alla scrittura di moduli

Ma cosa sono i moduli? Un modulo di Linux non è nient'altro che un file oggetto, di solito creato per mezzo dell'opzione -c di gcc. Di per sè, il modulo è creato compilando un normale file in linguaggio C cui manca la funzione main(). Al suo posto sono presenti un paio di funzioni denominate init_module e cleanup_module:

Di solito init_module() o registra nel kernel un handler per i motivi più svariati, oppure rimpiazza una funzione del kernel con proprio codice (di solito esso chiamerà a sua volta la funzione originale). La funzione cleanup_module() ci si aspetta rifaccia in senso inverso le azioni compiute da init_module(), cosicché il modulo possa essere rimosso in sicurezza.

Per esempio, se avete scritto un file in C chiamato module.c (con init_module() e cleanup_module() al posto della funzione main() ) il codice può essere convertito in un modulo digitando:

        $ gcc -c {SOME-FLAGS} my_module.c

Tale comando crea un modulo chiamato module.o che può essere a questo punto caricato nel kernel per mezzo del comando 'insmod' :

        $ insmod module.o

Nella stessa maniera, per rimuovere il modulo potete impiegare il comando 'rmmod' :

        $ rmmod module

4.2 Creazione di thread in RTLinux

Un' applicazione realtime è di solito composta da svariati 'thread' di esecuzione. I thread sono processi alleggeriti che condividono il medesimo spazio di indirizzamento. In RTLinux, tutti i thread condividono lo spazio di indirizzamento del kernel Linux. Il vantaggio offerto dai thread è che il passaggio dall'uno all'altro è piuttosto efficiente se comparato con un normale passaggio di contesto. Gli esempi che seguono illustrano come il controllo completo dell'esecuzione di un thread possa essere ottenuto usando una serie di funzioni.

4.3 Un programma di esempio

Il miglior modo per capire come lavora un thread è di seguire passo passo un programma realtime. Per esempio, il programma mostrato sotto verrà eseguito una volta al secondo e durante ciascuna iterazione mostrerà il messaggio 'Hello World'.

Il codice sorgente del programma (file - hello.c) :

#include <rtl.h>
#include <time.h>
#include <pthread.h>

pthread_t thread;

void * thread_code(void)
{
        pthread_make_periodic_np(pthread_self(), gethrtime(), 1000000000);

        while (1)
        {
                pthread_wait_np ();
                rtl_printf("Hello World\n");
        }

        return 0;
}

int init_module(void) 
{
   return pthread_create(&thread, NULL, thread_code, NULL);
}

void cleanup_module(void) 
{
   pthread_delete_np(thread);
}

Iniziamo da init_module(). Tale funzione richiama pthread_create(). Questi crea un nuovo thread che viene eseguito in contemporanea al thread chiamante. pthread_create() deve essere chiamata unicamente dal thread nel kernel Linux (per esempio da init_module()).

        int  pthread_create(pthread_t  * thread,
                            pthread_attr_t * attr,
                            void * (*thread_code)(void *),
                            void * arg);

Il nuovo thread creato è di tipo pthread_t, definito nell'header pthread.h. Tale thread consiste nella funzione thread_code() a cui viene passato arg come parametro. Il parametro attr serve a specificare quali attributi debbano essere applicati al nuovo thread. Se attr è NULL, esso avrà gli attributi predefiniti.

In questo caso thread_code() è chiamato senza parametri. thread_code() è composto da tre spezzoni - inizializzazione, corpo e chiusura.

Nella fase di inizializzazione viene chiamata la funzione pthread_make_periodic_np().

        int pthread_make_periodic_np(pthread_t thread, 
                                     hrtime_t start_time, 
                                     hrtime_t period);

pthread_make_periodic_np marca il thread come pronto per essere eseguito. Il thread inizierà all'istante start_time e sarà invocato a intervalli regolari, di durata pari al valore di period , espresso in nanosecondi.

gethrtime restituisce il tempo, sempre in nanosecondi, trascorso dal boot.

       hrtime_t gethrtime(void);

Questo valore non viene mai resettato o modificato. gethrtime ritorna sempre valori monotonicamente crescenti. hrtime_t è un intero con segno a 64 bit.

Attraverso la chiamata della funzione pthread_make_periodic_np(), il thread impone allo scheduler di eseguire periodicamente tale thread ad una frequenza di 1 Hz . Ciò segna la fine della sezione di inizializzazione del thread.

Il ciclo while() inizia con una chiamata alla funzione pthread_wait_np() che sospende l'esecuzione del thread realtime in esecuzione al momento, fino all'inizio del prossimo periodo. Il thread è stato precedentemente marcato per l'esecuzione con pthread_make_periodic_np. Una volta che il thread è richiamato di nuovo, esso esegue il contenuto rimanente del codice dentro il ciclo while() fino a quando non incontri un'altra chiamata a pthread_wait_np().

Visto che non è stata inclusa alcuna via d'uscita dal ciclo, questo thread continuerà ad essere eseguito ad una frequenza di 1Hz. L'unica maniera per interrompere il programma consiste nel rimuoverlo dal kernel col comando rmmod. Questo porta alla chiamata di cleanup_module(), che a sua volta invoca pthread_delete_np() per eliminare il thread e deallocare le sue risorse.


Avanti Indietro Indice