coop.c
Go to the documentation of this file.00001 00040 #include "proc_p.h" 00041 #include "proc.h" 00042 00043 // Log settings for cfg/log.h. 00044 #define LOG_LEVEL KERN_LOG_LEVEL 00045 #define LOG_FORMAT KERN_LOG_FORMAT 00046 #include <cfg/log.h> 00047 00048 #include <cpu/irq.h> 00049 #include <cpu/types.h> 00050 #include <cpu/attr.h> 00051 #include <cpu/frame.h> 00052 00059 EXTERN_C void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **save_sp); 00060 00061 00066 static void proc_schedule(void) 00067 { 00068 cpu_flags_t flags; 00069 00070 ATOMIC(LIST_ASSERT_VALID(&ProcReadyList)); 00071 ASSERT_USER_CONTEXT(); 00072 IRQ_ASSERT_ENABLED(); 00073 00074 /* Poll on the ready queue for the first ready process */ 00075 IRQ_SAVE_DISABLE(flags); 00076 while (!(CurrentProcess = (struct Process *)list_remHead(&ProcReadyList))) 00077 { 00078 /* 00079 * Make sure we physically reenable interrupts here, no matter what 00080 * the current task status is. This is important because if we 00081 * are idle-spinning, we must allow interrupts, otherwise no 00082 * process will ever wake up. 00083 * 00084 * During idle-spinning, an interrupt can occur and it may 00085 * modify \p ProcReadyList. To ensure that compiler reload this 00086 * variable every while cycle we call CPU_MEMORY_BARRIER. 00087 * The memory barrier ensure that all variables used in this context 00088 * are reloaded. 00089 * \todo If there was a way to write sig_wait() so that it does not 00090 * disable interrupts while waiting, there would not be any 00091 * reason to do this. 00092 */ 00093 IRQ_ENABLE; 00094 CPU_IDLE; 00095 MEMORY_BARRIER; 00096 IRQ_DISABLE; 00097 } 00098 IRQ_RESTORE(flags); 00099 } 00100 00101 void proc_switch(void) 00102 { 00103 /* Remember old process to save its context later */ 00104 Process * const old_process = CurrentProcess; 00105 00106 proc_schedule(); 00107 00108 /* 00109 * Optimization: don't switch contexts when the active 00110 * process has not changed. 00111 */ 00112 if (CurrentProcess != old_process) 00113 { 00114 cpu_stack_t *dummy; 00115 00116 #if CONFIG_KERN_MONITOR 00117 LOG_INFO("Switch from %p(%s) to %p(%s)\n", 00118 old_process, proc_name(old_process), 00119 CurrentProcess, proc_currentName()); 00120 #endif 00121 00122 /* Save context of old process and switch to new process. If there is no 00123 * old process, we save the old stack pointer into a dummy variable that 00124 * we ignore. In fact, this happens only when the old process has just 00125 * exited. 00126 * TODO: Instead of physically clearing the process at exit time, a zombie 00127 * list should be created. 00128 */ 00129 asm_switch_context(&CurrentProcess->stack, old_process ? &old_process->stack : &dummy); 00130 } 00131 00132 /* This RET resumes the execution on the new process */ 00133 } 00134 00135 00139 void proc_yield(void) 00140 { 00141 ATOMIC(SCHED_ENQUEUE(CurrentProcess)); 00142 proc_switch(); 00143 }
