Corso di AmigaOS

Torna all'elenco delle lezioniPer dubbi, consigli o richieste, potete mandare un'e-mail ad Andrea Carolfi.
Ringraziamo Amiga Transactor Mailing List per questo tangibile contributo!


I task (Quinta lezione)

In questa lezione cominceremo a vedere gli eseguibili Amiga. Questi sono divisi in task e processi.
La differenza più importante tra task e processo è che il primo, essendo ad un livello più basso, non può usare la dos.library e nemmeno chiamare funzioni che la potrebbero usare (file, librerie su disco da aprire), il secondo invece non ha queste limitazioni.

Le funzioni e procedure che exec ci mette a disposizione sono:

  • 1. APTR AddTask( struct Task *task, APTR initPC, APTR finalPC );
  • 2. void RemTask( struct Task *task );
  • 3. struct Task *FindTask( UBYTE *name );
  • 4. BYTE SetTaskPri( struct Task *task, long priority );
  • 5. ULONG SetSignal(unsigned long newSignals, unsigned long signalSet);
  • 6. ULONG SetExcept(unsigned long newSignals, unsigned long signalSet);
  • 7. ULONG Wait( unsigned long signalSet );
  • 8. void Signal( struct Task *task, unsigned long signalSet );
  • 9. BYTE AllocSignal( long signalNum );
  • 10. void FreeSignal( long signalNum );
  • 11. LONG AllocTrap( long trapNum );
  • 12. void FreeTrap( long trapNum );
  • void ChildFree( APTR tid );
  • void ChildOrphan( APTR tid );
  • void ChildStatus( APTR tid );
  • void ChildWait( APTR tid );

Tralasciamo le varie ChildXXX che non sono documentate e che non ho la più pallida idea di cosa facciano (anche se ho una vaga intuizione). Vediamo prima le più semplici. La funzione FindTask ha la stessa funzione delle precedenti FindXXX, ovvero ricercare un dato task nella lista di exec; con la caratteristica in più che se viene chiamata con NULL come parametro, restituirà il puntatore del task chiamante. Questo è molto utile per utilizzare la funzione SetTaskPri sul proprio task; come dice il nome, questa serve per impostare una nuova priorità al task specificato, ritornando la vecchia priorità.

Ci sono poi le funzioni 5, 7, 8, 9 e 10 che servono un po' come la Signal e la Alarm sui sistemi unix. Infatti è possibile richiedere al sistema di riservare un determinato segnale per poi rimanere in attesa di questo.
I segnali disponibili per task sono 32 (da 0 a 31), di cui i primi 16 per l'utente. Se viene specificato come parametro -1, la funzione ritornerà il primo segnale libero. Una volta che il segnale è stato allocato, ci si può porre in sua attesa con la funzione Wait. Spetterà poi ad un altro task (o allo stesso sistema operativo, a seconda del tipo di segnale richiesto) risvegliare il task con una Signal. Finito di usare il segnale, lo si potrà restituire con una FreeSignal.
Infine, la SetSignal serve per impostare o leggere il valore di un segnale usando una maschera. Per esempio, per controllare e reimpostare il segnale <CTRL-C>:

if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
{
        printf("Hai premuto CTRL-C!\n");
}

Bisogna però rendere noto, come fa infatti la documentazione di sistema, che queste funzioni sono a basso livello e che in pratica vengono usate dal sistema operativo per realizzare le porte messaggi. Infatti, se avessimo due porte messaggi dal quale voler aspettare, dovremo utilizzare questo frammento di codice:

[...]

struct MsgPort *port1,*port2;
ULONG sigs1,sigs2,signals;
[...]
sigs1 = 1L << port1 -> mp_SigBit;
sigs2 = 1L << port2 -> mp_SigBit;
signals = Wait(sigs1 | sigs2);
if(signals & sigs1)
{
        [...]
}
else if(signals & sigs2)
{
        [...]
}
else
{
        [...]
}

[...]

Adattandolo ovviamente alle proprie esigenze. Per esempio, se volessimo ricevere messaggi da due finestre aperte (anticipo un attimo le future lezioni):

[...]

struct Window *win,win2;
ULONG sigs1,sigs2,signals;
sigs1 = (1L  << win -> UserPort -> mp_SigBit);
sigs2 = (1L  << win2 -> UserPort -> mp_SigBit);
signals = Wait(sigs1 | sigs2);

[...]

AllocTrap, FreeTrap e SetExcept, servono le prime per richiedere e poi poter rilasciare una TRAP della CPU per poter rimpiazzare il codice di default con del proprio. Invece, la SetExcept serve per impostare un'eccezione.
Le trappole che mette a disposizione exec sono quelle associate all'istruzione assembly TRAP. Infatti la AllocTrap può essere chiamata con un numero compreso tra 0 e 15 o -1 per nessuna preferenza. Solitamente trap ed eccezioni servono a gestori di hardware, o di interrupt, ovvero programmi a bassissimo livello: È difficile che un programma MUI richieda un'eccezione.

Rimangono per ultime le funzioni AddTask e RemTask. Come il loro nome spiega, servono per aggiungere e rimuovere un task dalla lista di sistema. Notare che tutte le risorse allocate, dovranno essere deallocate precedentemente o non saranno rilasciate. La funzione RemTask, libera le liste di memoria presenti nella lista tc_MemEntry della struttura Task, che ora vedremo.

Per creare un task, ci viene in contro la funzione CreateTask della amiga.lib:

struct Task *CreateTask(STRPTR name,LONG pri,funcEntry initPC,
                               ULONG stackSize);

Questa funzione, si preoccupa di allocare tutto il necessario e di chiamare internamente la AddTask per accodare il task appena creato. Inoltre inizializza il campo tc_MemEntry in modo che quello che è stato allocato dalla CreateTask venga rimosso dalla RemTask. Vediamo una chiamata tipica di questa funzione:

extern void functionName();
char *tname = "unique name";
struct Task *task;

task = CreateTask(tname,0L,functionName,4000L);

crea un task di nome unique name, a priorità 0 e con 4000 byte di stack facendo partire l'esecuzione dalla funzione functionName che risiede in un modulo esterno a quello chiamante che sarà stato compilato senza il controllo dello stack poiché è dinamico.
Vediamo dunque la struttura Task:

/* Please use Exec functions to modify task structure fields, where
available.
 */
struct Task {
         struct  Node tc_Node;
         UBYTE   tc_Flags;
         UBYTE   tc_State;
         BYTE    tc_IDNestCnt;      /* intr disabled nesting*/
         BYTE    tc_TDNestCnt;      /* task disabled nesting*/
         ULONG   tc_SigAlloc;       /* sigs allocated */
         ULONG   tc_SigWait;        /* sigs we are waiting for */
         ULONG   tc_SigRecvd;       /* sigs we have received */
         ULONG   tc_SigExcept;      /* sigs we will take excepts for */
         UWORD   tc_TrapAlloc;      /* traps allocated */
         UWORD   tc_TrapAble;       /* traps enabled */
         APTR    tc_ExceptData;     /* points to except data */
         APTR    tc_ExceptCode;     /* points to except code */
         APTR    tc_TrapData;       /* points to trap data */
         APTR    tc_TrapCode;       /* points to trap code */
         APTR    tc_SPReg;          /* stack pointer     */
         APTR    tc_SPLower;        /* stack lower bound    */
         APTR    tc_SPUpper;        /* stack upper bound + 2*/
         VOID    (*tc_Switch)();    /* task losing CPU    */
         VOID    (*tc_Launch)();    /* task getting CPU  */
         struct  List tc_MemEntry;  /* Allocated memory. Freed by RemTask()*/
         APTR    tc_UserData;       /* For use by the task; no restrictions! */
};

A questo punto, siccome ad inizio lezione avevamo introdotto la differenza tra task e processo, vediamo quindi le procedure e funzioni che ci mette a disposizione, questa volta la dos.library:

struct MsgPort *CreateProc( STRPTR name, long pri, BPTR segList,
        long stackSize );
struct Process *CreateNewProc( struct TagItem *tags );
struct Process *CreateNewProcTagList( struct TagItem *tags );
struct Process *CreateNewProcTags( unsigned long tag1type, ... );
LONG RunCommand( BPTR seg, long stack, STRPTR paramptr, long paramlen );
struct Process *FindCliProc( unsigned long num );
BPTR LoadSeg( STRPTR name );
void UnLoadSeg( BPTR seglist );
BPTR NewLoadSeg( STRPTR file, struct TagItem *tags );
BPTR NewLoadSegTagList( STRPTR file, struct TagItem *tags );
BPTR NewLoadSegTags( STRPTR file, unsigned long tag1type, ... );

Vedremo nel dettaglio queste procedure e funzioni nella prossima lezione.

Lezione precedente Indice delle lezioni Lezione successiva
Copyright AMiWoRLD Ph0ton