// We enter as oldThread, but we return as newThread. // Returns with newThread's registers and stack. void thread_switch(oldThreadTCB, newThreadTCB) { pushad; // Push general register values onto the old stack. oldThreadTCB->sp = %esp; // Save the old thread's stack pointer. %esp = newThreadTCB->sp; // Switch to the new stack. popad; // Pop register values from the new stack. return; } void thread_yield() { TCB *chosenTCB, *finishedTCB; // Prevent an interrupt from stopping us in the middle of a switch. disableInterrupts(); // Choose another TCB from the ready list. chosenTCB = readyList.getNextThread(); if (chosenTCB == NULL) { // Nothing else to run, so go back to running the original thread. } else { // Move running thread onto the ready list. runningThread->state = #\readyThreadState#; readyList.add(runningThread); thread_switch(runningThread, chosenTCB); // Switch to the new thread. runningThread->state = #\runningThreadState#; } // Delete any threads on the finished list. while ((finishedTCB = finishedList->getNextThread()) != NULL) { delete finishedTCB->stack; delete finishedTCB; } enableInterrupts(); } // thread_create must put a dummy frame at the top of its stack: // the return PC and space for pushad to have stored a copy of the registers. // This way, when someone switches to a newly created thread, // the last two lines of thread_switch work correctly. void thread_dummySwitchFrame(newThread) { *(tcb->sp) = stub; // Return to the beginning of stub. tcb->sp--; tcb->sp -= SizeOfPopad; }