void schedule(void) { ..................... Check the Bottom Half ..................... do_Context_Switch = 0; spin_lock(&(scheduler->sched_lock)); -------------(1) heir_thread=scheduler->heir_thread(curr_thread); if (!heir_thread) { heir_thread=idle_thread; } #ifdef DEBUG0 assert(heir_thread->magic_key==MAGIC_KEY); #endif if (heir_thread!=curr_thread) { struct tcb *out_thread=curr_thread; curr_thread=heir_thread; CPU_Context_Switch(&(out_thread->thread_context), &(heir_thread->thread_context)); } spin_unlock(&(scheduler->sched_lock)); ----------(2) do_Context_Switch=1; }
schedule() finds the next thread to execute, by querying the scheduler object. If the next thread is not the same as the current thread, it then calls H/W dependent routine CPU_Context_Switch() for executing the context switch.
As with any other thread library function, this function also locks a variable (statement 1), and disables context switch before calling the scheduler API function hier_thread(). So when a thread is switched out of CPU it carries the lock with it. This however is not a problem if the thread which comes next onto the CPU was also switced out from the same point. That thread, when resumed, continues after the CPU_Context_Switch() function and hence unlocks the global variable at statement 2.
This is OK for all threads except for a thread which is going to execute for the first time, since then it does not start it's execution ast statement 2, but from the thread_init_function. Hence we have put a unlock and do_Context_Switch instruction at the start of thread_init_function.
void *thread_init_function(void *(*start_add)(void *),void *param) { spin_unlock(&(scheduler->sched_lock)); do_Context_Switch=1; start_add(param); /* Call the function from which the thread starts */ ............... }