Exemplo n.º 1
0
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;
    }
}
Exemplo n.º 2
0
/**********************************************************************
												 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();
	}

}
Exemplo n.º 3
0
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));
    }
}
Exemplo n.º 4
0
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);
        }
    }
}
Exemplo n.º 5
0
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);
}
Exemplo n.º 6
0
/**********************************************************************
												 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();
	}


}
Exemplo n.º 7
0
/**********************************************************************
														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;
}
Exemplo n.º 8
0
/**********************************************************************
														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);
	
}
Exemplo n.º 9
0
/**********************************************************************
														 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();

}