void scheduler() { // Init no longer has children. Needs to close. if (jrb_empty(init->children)) { SYSHalt(); } if(dll_empty(readyQ)) { noop_flag = 1; noop(); } else { PCB *process; Dllist node; Jval registers; noop_flag = 0; process = (PCB *) malloc(sizeof(PCB)); node = dll_first(readyQ); // Get next node in queue dll_delete_node(node); // Node in memory. Delete off readyQ // Get registers from node registers = dll_val(node); process = (PCB *)jval_v(registers); // Update current process currentProcess = process; User_Base = process->base; User_Limit = process->limit; run_user_code(process->registers); } }
void KtSched() { K_t kt; JRB jb; unsigned int sp; unsigned int now; JRB tmp; Dllist dtmp; /* * start by recording the current stack contents in case * I'm descheduled * * this is where I return to when I'm rescheduled */ if(setjmp(ktRunning->jmpbuf) != 0) { FreeFinishedThreads(); /* * if we are being killed by another thread, jump through * the exitbuf */ if(ktRunning->die_now) { /* Jim: This used to longjmp to the exitbuf, but I changed it for two reasons: 1. It wasn't being removed from ktActive 2. Hell will be paid if it is ktOriginal. I believe kt_exit() is cleaner. I have not tested it. I should. */ kt_exit(); /* not reached */ } return; } start: if (!jrb_empty(ktSleeping)) { now = time(0); while(!jrb_empty(ktSleeping)) { kt = (K_t) jval_v(jrb_val(jrb_first(ktSleeping))); if(kt->wake_time > now) { break; } WakeKThread(kt); } } /* * if there is nothing left to run, exit. However, if there * are sleepers or a joinall, deal with them appropriately */ if(dll_empty(ktRunnable)) { /* * first, check for sleepers and deal with them */ if(!jrb_empty(ktSleeping)) { kt = jval_v(jrb_val(jrb_first(ktSleeping))); sleep(kt->wake_time - now); goto start; } /* * next, see if there is a joinall thread waiting */ jb = jrb_find_int(ktBlocked,0); if(jb != NULL) { WakeKThread((K_t)jval_v(jrb_val(jb))); goto start; } if(!jrb_empty(ktBlocked)) { if(Debug & KT_DEBUG) { fprintf(stderr, "All processes blocked, exiting\n"); fflush(stderr); } exit(1); } else { if(Debug & KT_DEBUG) { fprintf(stderr, "No runnable threads, exiting\n"); fflush(stderr); } exit(0); } fprintf(stderr, "We shouldn't get here\n"); exit(1); } /* Grab the first job of the ready queue */ dtmp = dll_first(ktRunnable); kt = (K_t) dtmp->val.v; dll_delete_node(dtmp); /* If it is runnable, run it */ if(kt->state == RUNNABLE) { ktRunning = kt; ktRunning->state = RUNNING; longjmp(ktRunning->jmpbuf,1); /* This doesn't return */ } /* * if we have never run before, set up initial stack and go */ if(kt->state == STARTING) { if(setjmp(kt->jmpbuf) == 0) { /* * get double word aligned SP -- stacks grow from high * to low */ sp = (unsigned int)&((kt->stack[kt->stack_size-1])); while((sp % 8) != 0) sp--; #ifdef LINUX /* * keep double word aligned but put in enough * space to handle local variables for KtSched */ kt->jmpbuf->__jmpbuf[JB_BP] = (int)sp; kt->jmpbuf->__jmpbuf[JB_SP] = (int)sp-1024; PTR_MANGLE(kt->jmpbuf->__jmpbuf[JB_SP]); #endif #ifdef SOLARIS /* * keep double word aligned but put in enough * space to handle local variables for KtSched */ kt->jmpbuf[JB_FP] = (int)sp; kt->jmpbuf[JB_SP] = (int)sp-1024; #endif /* * set ktRunning while we still have local variables */ kt->state = RUNNING; ktRunning = kt; /* * now jump onto the new stack */ longjmp(kt->jmpbuf,1); } else { /* * here we are on a new, clean stack -- touch nothing, * set the state, and call * * ktRunning is global so there is no local variable * problem * * borrow this stack to try and free the last thread * if there was one */ FreeFinishedThreads(); if(setjmp(ktRunning->exitbuf) == 0) { /* * if we were killed before we ran, skip the * function call */ if(ktRunning->die_now == 0) { ktRunning->func(ktRunning->arg); } } /* * we are back and this thread is done * * make it inactive */ jb = jrb_find_int(ktActive,ktRunning->tid); if(jb == NULL) { if(Debug & KT_DEBUG) { fprintf(stderr, "KtSched: panic -- inactive return\n"); fflush(stderr); } exit(1); } jrb_delete_node(jb); /* * look to see if there is a thread waiting for this * one to exit -- careful with locals */ jb = jrb_find_int(ktBlocked,ktRunning->tid); if(jb != NULL) { WakeKThread((K_t)jval_v(jrb_val(jb))); } /* * all we can do now is to commit suicide * * don't touch the locals; * * and don't free the stack we are running on */ FreeFinishedThreads(); ktRunning->state = DEAD; dll_append(ktFree_me,new_jval_v(ktRunning)); ktRunning = NULL; goto start; } } /* The only way we get here is if there was a thread on the runnable queue whose state was not RUNNABLE or STARTING. Flag that as an error */ fprintf(stderr, "Error: non-STARTING or RUNNABLE thread on the ready queue\n"); exit(1); }