int myThreadCreate(thread_t *pThread, void *(*pStartRoutine)(void *), void *pArgument, int pLimitTime, char *pSchedulerType) { if (threadsQueue != NULL) { sigprocmask(SIG_BLOCK, &sigProcMask, NULL); TCB newTCB = createNewTCB(); getcontext(&(newTCB->threadContext)); if (newTCB == NULL) { freeThread(newTCB); sigprocmask(SIG_UNBLOCK, &sigProcMask, NULL); return NOT_ENOUGH_MEMORY; } else { if(pLimitTime > 0) { newTCB->limitTime = pLimitTime; } newTCB->threadContext.uc_link = &exitContext; newTCB->startQuantum = threadsQueue->quantums; setSchedulerType(newTCB, pSchedulerType); makecontext(&(newTCB->threadContext), wrapperFunction, 2, pStartRoutine, pArgument); *pThread = newTCB->threadID; //printf("MyThread: Nuevo thread creado: %ld\n", *pThread); insertThread(threadsQueue, newTCB); sigprocmask(SIG_UNBLOCK, &sigProcMask, NULL); return SUCESS; } } else { return MY_THREAD_NOT_INITIALIZED; } }
/********************************************************************** TLB_HANDLER Caricato all'arrivo di una eccezione di tipo TLBTRAP. Affida il controllo del thread corrente ad un Trap Manager, se specificato, altrimenti viene terminato tutto il sottoalbero corrispondente. **********************************************************************/ void tlb_handler(){ tcb_t *manager; /* TUTTE le operazioni sono equivalenti a quelle per SYSBP */ current_thread->cpu_slice += (GET_TODLOW - current_thread_tod); current_thread->cpu_time += (GET_TODLOW - current_thread_tod); save_state(tlbtrap_oldarea, &(current_thread->t_state)); manager = current_thread->tlbtrap_manager_thread; if (manager == NULL) { terminate(current_thread); current_thread = NULL; scheduler(); } else { send(current_thread, manager, tlbtrap_oldarea->cause); current_thread->waiting_for = manager; insertThread(&wait_queue, current_thread); current_thread = NULL; scheduler(); } }
void schedule() { /* azioni da compiere quando non c'e' nessun thread pronto ad eseguire */ if (emptyThreadQ(&readyQueue) && currentThread == NULL) { prova(); if (threadCount == 1)/* se c'e' solo il SSI -> normal system shutdown */ HALT(); /* chiamo la HALT ROM routine */ else if (threadCount > 0 && softBlockCount == 0) {/* deadlock */ PANIC(); /* chiamo la PANIC ROM routine */ } else if (threadCount > 0 && softBlockCount > 0) { /* in attesa di un interrupt -> wait state */ /* se ci sono thread in attesa dello pseudo tick, * carico il valore dello pseudo clock nel registro della cpu.*/ if (!emptyThreadQ(&waitForPseudoClockQueue)) { SET_IT(SCHED_PSEUDO_CLOCK); } /* impostiamo lo stato del processore con gli interrupt abilitati*/ setSTATUS(getSTATUS() | STATUS_IEc | STATUS_INT_UNMASKED); for (;;); } } else { /* Se non c'è nessun Thread in esecuzione ma c'e n'è almeno uno nella readyQueue allora carico un thread*/ if (currentThread == NULL) { currentThread = removeThread(&readyQueue); currentThread->elapsedTime = 0; currentThread->startTime = GET_TODLOW; SET_IT(SCHED_TIME_SLICE); /* Altrimenti se è passato il SCHED_TIME_SLICE rimuovo il thread corrente dall'esecuzione*/ } else if (currentThread->elapsedTime >= SCHED_TIME_SLICE) { //in questo modo do priorità all'SSI if (currentThread != tcb_SSI) { insertThread(&readyQueue, currentThread); /*Carico un nuovo thread*/ currentThread = removeThread(&readyQueue); } currentThread->elapsedTime = 0; currentThread->startTime = GET_TODLOW; /* Se e' scattato lo pseudo clock non settiamo il timer a 5 ms * dato che scattera' subito l'interrupt dello pseudo clock */ if (!isPseudoClock) SET_IT(SCHED_TIME_SLICE); } /* carico lo stato del thread nel processore dalla sua tcb */ LDST(&(currentThread->t_state)); } }
void myThreadInit(long pTimeInterval) { //DEBUGGING debuggingFile = fopen("DebuggingFile.txt", "w"); //DEBUGGING if (threadsQueue == NULL && deadThreadsQueue == NULL) { sigemptyset(&sigProcMask); sigaddset(&sigProcMask, SIGPROF); deadThreadsQueue = createDeadTheadsNodesQueue(); threadsQueue = createTCBQueue(); if (deadThreadsQueue == NULL || threadsQueue == NULL) { return; } else { srand((unsigned) time(&randomTimeSeed)); timeInterval = pTimeInterval * 1000; threadsQueue->quantum = pTimeInterval; TCB TCBMain = createNewTCB(); getcontext(&(TCBMain->threadContext)); setExitContext(); TCBMain->threadContext.uc_link = &exitContext; //La linea de abajo indica que el thread principal es administrado por el scheduler RoundRobin. // TCBMain->roundRobin = 1; // roundRobinControl = 1; // Descomentar las lineas comentadas de abajo y comentar la linea de arriba si se quiere que el thread principal sea administrado por el scheduler Sort. TCBMain->sort = 1; int nextTicket = searchEndTicket(threadsQueue); TCBMain->initialTicket = nextTicket; TCBMain->finalTicket = nextTicket; sortControl = 1; // threadsQueue->currentThread = TCBMain; insertThread(threadsQueue, TCBMain); memset(&schedulerHandle, 0, sizeof (schedulerHandle)); schedulerHandle.sa_handler = &realTime; sigaction(SIGPROF, &schedulerHandle, NULL); //printf("\nMyThread: Biblioteca MyThread Inicializada...\n"); timeQuantum.it_value.tv_sec = 0; timeQuantum.it_value.tv_usec = timeInterval; timeQuantum.it_interval.tv_sec = 0; timeQuantum.it_interval.tv_usec = timeInterval; setitimer(ITIMER_PROF, &timeQuantum, NULL); } } }
MprThreadService::MprThreadService() { #if BLD_DEBUG pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); memset(&listLock, 0, sizeof(listLock)); pthread_mutex_init(&listLock, &attr); pthread_mutexattr_destroy(&attr); #endif mutex = new MprMutex(); // // Don't actually create the thread. Just create a thead object for // this main thread // mainThread = new MprThread(MPR_NORMAL_PRIORITY, "main"); mainThread->setOsThread(pthread_self()); insertThread(mainThread); }
/********************************************************************** SYSBP_HANDLER Caricato all'arrivo di una eccezione di tipo SYSCALL/BREAKPOINT. Fornisce principalmente il servizio di message passing. In tutti i casi in cui è sollevata una eccezione diversa da SYSCALL di tipo 1 o 2 in Kernel Mode, questa routine, come le altre due di questo modulo affidano il controllo del thread corrente ad un Trap Manager, se specificato, altrimenti viene terminato tutto il sottoalbero corrispondente. **********************************************************************/ void sysbp_handler(){ int exc_cause; int KUmode; /* 0 se Kernel / 1 se User */ tcb_t *trapped; tcb_t *manager; tcb_t *sender; tcb_t *receiver; U32 payload; U32 *reply; /* Aggiornamento tempo thread */ current_thread->cpu_slice += (GET_TODLOW - current_thread_tod); current_thread->cpu_time += (GET_TODLOW - current_thread_tod); /* Salvo lo stato del processore del thread che ha sollevato l'eccezione, nel campo t_state del suo tcb. Lo stato è salvato nella old area dell'attuale eccezione. Modifico opportunamente il PC per non avere un ciclo nel ritorno dall'eccezione. */ save_state(sysbk_oldarea, &(current_thread->t_state)); current_thread->t_state.pc_epc += WORD_SIZE; /* Recupero il tipo di eccezione avvenuta */ exc_cause = CAUSE_EXCCODE_GET(sysbk_oldarea->cause); /* Controllo se Kernel o User Mode */ KUmode = (sysbk_oldarea->status & STATUS_KUp) >> 3; /* Se l'eccezione è una SYSCALL 1 o 2 ed eseguita in kernel mode */ if (KUmode == 0) { if (exc_cause == EXC_SYSCALL) { /* MsgSend */ if (sysbk_oldarea->reg_a0 == SEND) { sender = current_thread; payload = sysbk_oldarea->reg_a2; /* Protezione SSI e incremento thread in attesa di servizio */ if (sysbk_oldarea->reg_a1 == MAGIC_SSI) { receiver = SSI_tcb; soft_block_count++; } else receiver = ((tcb_t *)(sysbk_oldarea->reg_a1)); /* CASO TRAP MANAGER --> Intercettare messaggio TRAPTERMINATE / TRAPCONTINUE */ if ((thereIs_manager(sender)) && (receiver->waiting_for == sender)) { /*** TRAPTERMINATE ***/ if (payload == TRAPTERMINATE) { trapped = receiver; terminate(trapped); /* Termino thread in wait_queue in attesa della decisione del Trap Manager */ scheduler(); } /*** TRAPCONTINUE ***/ if (payload == TRAPCONTINUE) { trapped = receiver; insertThread(&ready_queue, outThread(&wait_queue, trapped)); /* Altrimenti lo risveglio */ scheduler(); } } /* Caso normale di MsgSend (vedi send) */ sender->t_state.reg_v0 = send (sender, receiver, payload); scheduler(); } /* MsgRecv */ if (sysbk_oldarea->reg_a0 == RECV) { receiver = current_thread; reply = (U32 *)sysbk_oldarea->reg_a2; /* Protezione SSI (non decremento qui soft block count ma al momento di ricevimento servizio) */ if (sysbk_oldarea->reg_a1 == MAGIC_SSI) sender = SSI_tcb; else sender = ((tcb_t *)(sysbk_oldarea->reg_a1)); /* MsgRecv (vedi recv) e restituisco sender direttamente (nel caso NON BLOCCANTE e non con SSIRequest) */ current_thread->t_state.reg_v0 = (U32)recv(current_thread, ((tcb_t *)sysbk_oldarea->reg_a1), ((U32 *)sysbk_oldarea->reg_a2)); scheduler(); } } } /* TUTTI gli altri casi*/ manager = current_thread->sysbp_manager_thread; /* Se il thread NON ha specificato un Trap Management thread per questa eccezione viene terminato */ if (manager == NULL) { terminate(current_thread); current_thread = NULL; scheduler(); } /* Se il thread HA invece specificato il gestore viene freezato */ else { /* Invio messaggio al suo Trap manager con registro cause come payload */ send(current_thread, manager, sysbk_oldarea->cause); /* Setto in TCB chi sto aspettando */ current_thread->waiting_for = manager; /* Freeze del thread in attesa della decisione del manager */ insertThread(&wait_queue, current_thread); current_thread = NULL; scheduler(); } }
/********************************************************************** RECV Mette in wait per un messaggio (settando prima gli opportuni campi ausiliari nella struttura del tcb richiedente) se non vi è il messaggio cercato nella inbox (o un qualsiasi messaggio per ANYMESSAGE). Caso BLOCCANTE. Altrimenti viene creata l'astrazione del messaggio ricevuto restituendo il payload inviato al thread all'indirizzo indicato nel registro a2 (reply) ---> CASO NON BLOCCANTE. **********************************************************************/ tcb_t *recv (tcb_t *receiver, tcb_t *sender, U32 *reply){ msg_t *msg; /* Caso ANYMESSAGE, attesa di un qualsiasi messaggio */ if (sender == ANYMESSAGE) { /* Cerco di estrarre il primo messaggio, se c'è */ msg = popMessage(&(receiver->t_inbox), NULL); /* Inbox vuota -> wait */ if (msg == NULL) { /* Per chi sono fermo */ receiver->waiting_for = ANYMESSAGE; /* Dove aspetto la risposta */ receiver->reply = reply; /* Metto in wait_queue */ insertThread(&wait_queue, receiver); current_thread = NULL; return NULL; } /* Inbox NON vuota -> preleva messaggio */ else { *reply = msg->m_message; sender = msg->m_sender; /* Restituisco il messaggio alla lista dei liberi */ freeMsg(msg); /* Restituisco il mittente del messaggio */ return(sender); } } /* Caso THREAD SPECIFICATO */ else if (sender != ANYMESSAGE) { /* Cerco di estrarre il messaggio inviato dal thread specificato */ msg = popMessage(&(receiver->t_inbox), sender); /* Messaggio non trovato -> wait */ if (msg == NULL) { /* Per chi sono fermo */ receiver->waiting_for = sender; /* Dove aspetto la risposta */ receiver->reply = reply; /* Metto in wait_queue */ insertThread(&wait_queue, receiver); current_thread = NULL; return NULL; } /* Messaggio trovato -> preleva messaggio */ else { *reply = msg->m_message; /* Se prelevo risposta ad un servizio decremento soft_block_count */ if (sender == (tcb_t *)MAGIC_SSI) soft_block_count--; /* Restituisco il messaggio alla lista dei liberi */ freeMsg(msg); /* Restituisco il mittente del messaggio */ return(sender); } } return NULL; }
/********************************************************************** SEND Invia un messaggio come richiesto dal sender al destinatario specificato nel registro a1 (receiver), col payload specificato al registro a2 (payload). Operazione NON BLOCCANTE. **********************************************************************/ int send (tcb_t *sender, tcb_t *target, U32 payload){ msg_t *msg; tcb_t *_sender_; /* Protezione SSI */ if (sender == SSI_tcb) _sender_ = (tcb_t *)MAGIC_SSI; else _sender_ = sender; /* Destinatario in ready_queue o thread corrente */ if ( ((thereIsThread(&ready_queue, target)) != NULL ) || (current_thread == target) ) { if ((msg = allocMsg()) == NULL) PANIC(); /* Creazione e compilazione messaggio */ msg->m_sender = _sender_; msg->m_message = payload; /* Priorità allo Pseudo Clock Tick -> Messaggio in testa */ if (_sender_ == (tcb_t*)BUS_INTERVALTIMER) pushMessage(&(target->t_inbox), msg); /* Trattamento normale -> Messaggio in coda */ else insertMessage(&(target->t_inbox), msg); return (MSGGOOD); } /* Destinatario in wait_queue */ else if ((thereIsThread(&wait_queue, target)) != NULL ) { /* Se sta aspettando un messaggio da questo thread o da chiunque sveglio il thread dest togliendolo dalla wait_queue e lo inserisco nella ready_queue passandogli il payload dove mi aveva richiesto e che avevo salvato nel TCB nel campo "reply". */ if ((target->waiting_for == _sender_) || (target->waiting_for == ANYMESSAGE)) { *(target->reply) = payload; /* Risveglio il thread */ insertThread(&ready_queue, outThread(&wait_queue, target)); /* Risettaggio campi per message passing */ target->waiting_for = (tcb_t *)-1; target->reply = (U32 *)-1; /* Decremento soft block count se caso SSI e restituisco sender al destinatario */ if (_sender_ == SSI_tcb) soft_block_count--; target->t_state.reg_v0 = (U32)_sender_; return (MSGGOOD); } /* Destinatario momentaneamente in attesa di un altro mittente */ else { /* Tutto come sopra */ if ((msg = allocMsg()) == NULL) PANIC(); msg->m_sender = _sender_; msg->m_message = payload; if (sender == (tcb_t *)BUS_INTERVALTIMER) pushMessage(&(target->t_inbox), msg); else insertMessage(&(target->t_inbox), msg); return (MSGGOOD); } } /* Nessuno dei casi precedenti --> potrebbe essere stato terminato il thread */ return (MSGNOGOOD); }
/********************************************************************** INT_HANDLER Caricato all'arrivo di un interrupt, scandisce sequenzialmente, quindi garantendo priorità, le linee, da quelle con indice minore (più veloci) a quelle con indice maggiore (più lente). Ciò viene fatto in base ai bit IP del registro CAUSE, cercando poi quale/i device fra gli 8 possibili ha generato l'interrupt. A questo punto viene gestito l'interrupt, mandando un messaggio a SSI e ACKando il device register, principalmente, più altre azioni a seconda dello specifico device. **********************************************************************/ void int_handler(){ int int_cause; int *status; int *status_trans; int *status_rec; int *int_bitmap; int *command; int *command_trans; int *command_rec; memaddr device_baseaddr; int dev_number; /* Se c'era un processo sulla CPU salvo il precedente stato del processore nel campo t_state del tcb attivo in quel momento. Lo stato è salvato nella old area dell'attuale eccezione. */ if (current_thread != NULL) { /* Aggiornamento tempo thread */ current_thread->cpu_slice += (GET_TODLOW - current_thread_tod); current_thread->cpu_time += (GET_TODLOW - current_thread_tod); /* Salvataggio stato */ save_state(int_oldarea, &(current_thread->t_state)); } /* Prelevo registro cause */ int_cause = int_oldarea->cause; /* Non presenti interrupt da linee 0 e 1 (software) in AmiKaya11 */ /* Linea 2 Interval Timer Interrupt + Gestione PSEUDO CLOCK ****************************/ if (CAUSE_IP_GET(int_cause, INT_TIMER)) { /* Aggiornamento pseudo clock */ pseudo_tick = pseudo_tick + (GET_TODLOW - start_pseudo_tick); start_pseudo_tick = GET_TODLOW; /* Interrupt per Pseudo-clock Tick */ if (pseudo_tick >= SCHED_PSEUDO_CLOCK) { /* Messaggio all'SSI che dovrà gestire lo sbloccaggio dei thread */ interrupt_msg_array[i].service = PSEUDOCLOCK_MSG; interrupt_msg_array[i].arg = 0; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)BUS_INTERVALTIMER, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); /* Faccio ripartire il clock del device virtuale */ pseudo_tick = 0; start_pseudo_tick = GET_TODLOW; } /* Gestione per Slice processo corrente scaduto */ if ((current_thread != NULL) && (current_thread->cpu_slice >= SCHED_TIME_SLICE)) { insertThread(&ready_queue, current_thread); current_thread = NULL; } /* Default */ else SET_IT(SCHED_PSEUDO_CLOCK - pseudo_tick); } /* Interval Timer ********************************************************************/ /* Linea 3 Disk interrupt **************************************************************/ else if (CAUSE_IP_GET(int_cause, INT_DISK)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_DISK - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_DISK - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo valore del campo Status del Device Register */ status = (int *)device_baseaddr; /* Puntatore a campo command del Device Register */ command = (int *)(device_baseaddr + 0x4); /* ACK al device */ *command = DEV_C_ACK; /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)device_baseaddr, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); } /* Disk ******************************************************************************/ /* Linea 4 Tape interrupt **************************************************************/ else if (CAUSE_IP_GET(int_cause, INT_TAPE)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_TAPE - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_TAPE - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo valore del campo Status del Device Register */ status = (int *)device_baseaddr; /* Puntatore a campo command del Device Register */ command = (int *)(device_baseaddr + 0x4); /* ACK al device */ *command = DEV_C_ACK; /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)device_baseaddr, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); } /* Tape ******************************************************************************/ /* Linea 5 Unused line interrupt *******************************************************/ else if (CAUSE_IP_GET(int_cause, INT_UNUSED)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_UNUSED - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_UNUSED - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo valore del campo Status del Device Register */ status = (int *)device_baseaddr; /* Puntatore a campo command del Device Register */ command = (int *)(device_baseaddr + 0x4); /* ACK al device */ *command = DEV_C_ACK; /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)device_baseaddr, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); } /* Unused ****************************************************************************/ /* Linea 6 Printer interrupt ***********************************************************/ else if (CAUSE_IP_GET(int_cause, INT_PRINTER)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_PRINTER - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_PRINTER - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo valore del campo Status del Device Register */ status = (int *)device_baseaddr; /* Puntatore a campo command del Device Register */ command = (int *)(device_baseaddr + 0x4); /* ACK al device */ *command = DEV_C_ACK; /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)device_baseaddr, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); } /* Printer ***************************************************************************/ /* Linea 7 Terminal interrupt **********************************************************/ else if (CAUSE_IP_GET(int_cause, INT_TERMINAL)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_TERMINAL - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_TERMINAL - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo lo stato e il puntatore al campo command del Device Register in trasmissione */ status_trans = (int *)(device_baseaddr + 0x8); command_trans = (int *)(device_baseaddr + 0xC); /* Salvo lo stato e il puntatore al campo command del Device Register in ricezione */ status_rec = (int *)device_baseaddr; command_rec = (int *)(device_baseaddr + 0x4); /* Analizzo lo stato per estrarre la causa dell'interrupt e agisco di conseguenza*/ /* Un carattere è stato trasmesso -> Priorità alla trasmissione */ if (((*status_trans) & STATUSMASK) == DEV_TTRS_S_CHARTRSM) { /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status_trans; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)status_trans, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); /* ACK al device */ *command_trans = DEV_C_ACK; } /* Un carattere è stato ricevuto */ else if (((*status_rec) & STATUSMASK) == DEV_TRCV_S_CHARRECV) { /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status_rec; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)status_rec, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); /* ACK al device */ *command_rec = DEV_C_ACK; } } /* Terminal **************************************************************************/ /* Incremento i in modo circolare */ i = (i+1)%48; scheduler(); }