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)); } }
/* * termina/elimina il TCB passato ponendo in stato READY_THREAD tutti i * thread che fossero in inbox e in oubox, questi ultimi vengono poi * re-inseriti nella ready_queue */ HIDDEN void force_terminate(tid_t bill) { tcb_t *bill_t, *tmp_bill; bill_t = resolveTid(bill); /* controllo presenza TCB in attesa in inbox */ while (!emptyThreadQ(bill_t->inbox)) { tmp_bill = removeThreadQ(&(bill_t->inbox)); tmp_bill->status = READY_THREAD; insertBackThreadQ(&ready_queue, tmp_bill); } /* controllo presenza TCB in attesa in outbox */ while (!emptyThreadQ(bill_t->outbox)) { tmp_bill = removeThreadQ(&(bill_t->outbox)); tmp_bill->status = READY_THREAD; insertBackThreadQ(&ready_queue, tmp_bill); } killTcb(bill); thread_count--; }
/* Rimuove il tcb_t puntato da p dalla coda la cui testa è puntata da head. Se l'elemento p non è presente nella coda allora restituisce NULL*/ tcb_t *outThread(struct list_head *head, tcb_t *p) { struct list_head *t_temp = NULL; /* se il puntatore a coda */ if(emptyThreadQ(head)) return NULL; /* cerco in tutta la lista se c'è una corrispondenza con con p */ list_for_each(t_temp, head) { if( t_temp == &(p->t_next) ) {/* nel caso la trovo allora la elimino e lo restituisco */ list_del( &(p->t_next) ); INIT_LIST_HEAD(&(p->t_next)); return p; } } /* altrimenti restituisco NULL */ return NULL; }
/* * 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 */ }
int main() { int i; initTcbs(); addokbuf("Initialized thread control blocks \n"); /* Check allocTcb */ for (i = 0; i < MAXPROC; i++) { if ((threadp[i] = allocTcb()) == NULL) adderrbuf("allocTcb(): unexpected NULL "); } if (allocTcb() != NULL) { adderrbuf("allocTcb(): allocated more than MAXPROC entries "); } addokbuf("allocTcb ok \n"); /* return the last 10 entries back to free list */ for (i = 10; i < MAXPROC; i++) freeTcb(threadp[i]); addokbuf("freed 10 entries \n"); /* create a 10-element thread queue */ qa = mkEmptyThreadQ(); if (!emptyThreadQ(qa)) adderrbuf("emptyThreadQ(qa): unexpected FALSE "); addokbuf("Inserting... \n"); for (i = 0; i < 10; i++) { if ((q = allocTcb()) == NULL) adderrbuf("allocTcb(): unexpected NULL while insert "); switch (i) { case 0: firstthread = q; break; case 5: midthread = q; break; case 9: lastthread = q; break; default: break; } insertBackThreadQ(&qa, q); } addokbuf("inserted 10 elements \n"); if (emptyThreadQ(qa)) adderrbuf("emptyThreadQ(qa): unexpected TRUE" ); /* Check outThreadQ and headThreadQ */ if (headThreadQ(qa) != firstthread) adderrbuf("headThreadQ(qa) failed "); q = outThreadQ(&qa, firstthread); if ((q == NULL) || (q != firstthread)) adderrbuf("outThreadQ(&qa, firstthread) failed on first entry "); freeTcb(q); q = outThreadQ(&qa, midthread); if (q == NULL || q != midthread) adderrbuf("outThreadQ(&qa, midthread) failed on middle entry "); freeTcb(q); if (outThreadQ(&qa, threadp[0]) != NULL) adderrbuf("outThreadQ(&qa, threadp[0]) failed on nonexistent entry "); addokbuf("outThreadQ() ok \n"); /* Check if removeThread and insertThread remove in the correct order */ addokbuf("Removing... \n"); for (i = 0; i < 8; i++) { if ((q = removeThreadQ(&qa)) == NULL) adderrbuf("removeThreadQ(&qa): unexpected NULL "); freeTcb(q); } if (q != lastthread) adderrbuf("removeThreadQ(): failed on last entry "); if (removeThreadQ(&qa) != NULL) adderrbuf("removeThreadQ(&qa): removes too many entries "); if (!emptyThreadQ(qa)) adderrbuf("emptyThreadQ(qa): unexpected FALSE "); addokbuf("insertThreadQ(), removeThreadQ() and emptyThreadQ() ok \n"); addokbuf("thread queues module ok \n"); addokbuf("After all, tomorrow is another day!\n"); return 0; }