Пример #1
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));
    }
}
Пример #2
0
/*
 * carica il processore con lo snapshot salvato nel TCB in testa
 * alla ready queue
 */
HIDDEN void upThread(void) {
	tcb_t *current;
	signed int time_snap;
	
	/* inizio del conteggio del tempo passato in codice kernel, solo per la prima
	 * esecuzione, altrimenti inizializzazione prevista negli vari handler */
	if (first_up) time_in_kernel = TOD_SNAPSHOT;

	current = removeThreadQ(&ready_queue);
	current_thread = current->tid;
	current->status = RUNN_THREAD;
	current = resolveTid(current_thread);
	if (current->cpu_remain == 0)
		current->cpu_remain = SCHED_TIME_SLICE;

	/* aggiorna il valore dello pseudo count evitando un possibile underflow */
	if (pseudo_count < (last_time_slice + STCK(time_snap) - time_in_kernel)) /* STCK piu' preciso */
		pseudo_count = 0;
	else
		pseudo_count -= last_time_slice + time_snap - time_in_kernel;

	/* settaggio interval timer considerando il tempo rimasto allo scadere dello pseudo clock*/
	if (pseudo_count > SCHED_TIME_SLICE) {
		if (current->cpu_remain < SCHED_TIME_SLICE) {
			last_time_slice = TOD_SNAPSHOT; /* inizio intervallo di tempo del prossimo time slice */
			SET_IT(current->cpu_remain); /* settaggio dell'interval timer */
		}
		else {
			last_time_slice = TOD_SNAPSHOT; /* inizio intervallo di tempo del prossimo time slice */
			SET_IT(SCHED_TIME_SLICE); /* settaggio dell'interval timer */
		}
	}
	else {
		last_time_slice = TOD_SNAPSHOT; /* inizio intervallo di tempo del prossimo time slice */
		SET_IT(pseudo_count); /* settaggio dell'interval timer */
	}
	/* carica il processore con lo stato del thread */
	LDST(&(current->cpu_snapshot));
	/* esegue codice del thread appena caricato */
}
Пример #3
0
/*
 * funzione principale
 */
void schedule(void) {
	tcb_t	*SSI_t, *tmp_q;
	unsigned int execKill;

	/* esami tutta la ready queue, spostando tutti i thread contrassegnati to_kill
	 * nella killable_queue. Inizia la scansione da capo ad ogni thread spostato */
	if (!emptyThreadQ(ready_queue)){
		tmp_q = ready_queue;
		do{
			execKill = FALSE;
			if(tmp_q->to_kill == TRUE){
				tmp_q = outThreadQ(&ready_queue, tmp_q);
				insertBackThreadQ(&killable_queue, tmp_q);
				execKill = TRUE;
			}
			tmp_q = tmp_q->t_prev;
			if (execKill == TRUE)
				tmp_q = ready_queue;
			if (emptyThreadQ(ready_queue))
				execKill = FALSE;
		} while(((tmp_q != ready_queue) && (!emptyThreadQ(ready_queue))) || execKill == TRUE);
	}

	/* termina tutti i thread, svuotando contestualmente killable_queue */
	if (!emptyThreadQ(killable_queue)){
		tmp_q = killable_queue;
		do{
			outThreadQ(&killable_queue, tmp_q);
			force_terminate(tmp_q->tid);
			tmp_q = tmp_q->t_prev;
		} while(!emptyThreadQ(killable_queue));
	}

	if (emptyThreadQ(ready_queue)) {
		if (thread_count == 1) HALT(); /* dovrebbe bastare questo tipo di controllo */
		SSI_t = resolveTid(SSI_TID);
		if (thread_count > 0 && softb_count == 0) PANIC();
		/* anche la SSI non puo' eseguire perche' e' in recv */
		if (thread_count > 0 && softb_count > 0 && SSI_t->status == W4_ANYTID) {
			all_blocked = TRUE; /* tutti i thread sospesi */
			last_time_slice = TOD_SNAPSHOT;
			SET_IT(pseudo_count); /* settaggio interval timer con il valore di pseudo clock */
			ENABLE_INTERRUPT;
			for (;;); /* aspetta una interrupt */
		}
	}
	upThread(); /* dispatch di un nuovo thread */
}
Пример #4
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();

}