Per dubbi, consigli o richieste, potete mandare un'e-mail ad Andrea Carolfi.
Ringraziamo Amiga Transactor Mailing List per questo tangibile contributo!
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:
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. 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. 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. /* 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.
|