preempt.c

Go to the documentation of this file.
00001 
00047 #include "cfg/cfg_proc.h"
00048 
00049 #if CONFIG_KERN_PREEMPT
00050 
00051 #include "proc_p.h"
00052 #include "proc.h"
00053 #include "idle.h"
00054 
00055 #include <kern/irq.h>
00056 #include <kern/monitor.h>
00057 #include <cpu/frame.h> // CPU_IDLE
00058 #include <cpu/irq.h>   // IRQ_DISABLE()...
00059 #include <drv/timer.h>
00060 #include <cfg/module.h>
00061 #include <cfg/depend.h>    // CONFIG_DEPEND()
00062 
00063 // Check config dependencies
00064 CONFIG_DEPEND(CONFIG_KERN_PREEMPT, CONFIG_KERN && CONFIG_TIMER_EVENTS && CONFIG_KERN_IRQ);
00065 
00066 MOD_DEFINE(preempt)
00067 
00068 
00069 cpu_atomic_t _preempt_forbid_cnt;
00070 
00071 static Timer preempt_timer;
00072 
00073 
00074 void proc_schedule(void)
00075 {
00076     IRQ_DISABLE;
00077 
00078     ASSERT(proc_allowed());
00079     LIST_ASSERT_VALID(&ProcReadyList);
00080     CurrentProcess = (struct Process *)list_remHead(&ProcReadyList);
00081     ASSERT2(CurrentProcess, "no idle proc?");
00082 
00083     IRQ_ENABLE;
00084 
00085     TRACEMSG("launching %p:%s", CurrentProcess, proc_currentName());
00086 }
00087 
00088 void proc_preempt(UNUSED_ARG(void *, param))
00089 {
00090     if (proc_allowed())
00091     {
00092         IRQ_DISABLE;
00093 
00094         #if CONFIG_KERN_PRI
00095             Process *rival = (Process *)LIST_HEAD(&ProcReadyList);
00096             if (rival && rival->link.pri >= CurrentProcess->link.pri)
00097             {
00098         #endif
00099 
00100         TRACEMSG("preempting %p:%s", CurrentProcess, proc_currentName());
00101 
00102 // FIXME: this still breaks havoc, probably because of some reentrancy issue
00103 #if 0
00104         SCHED_ENQUEUE(CurrentProcess);
00105         proc_schedule();
00106 #endif
00107         #if CONFIG_KERN_PRI
00108             }
00109         #endif
00110 
00111         IRQ_ENABLE;
00112     }
00113 
00114     timer_setDelay(&preempt_timer, CONFIG_KERN_QUANTUM);
00115     timer_add(&preempt_timer);
00116 }
00117 
00118 void proc_switch(void)
00119 {
00120     ATOMIC(LIST_ASSERT_VALID(&ProcReadyList));
00121     TRACEMSG("%p:%s", CurrentProcess, proc_currentName());
00122     ATOMIC(LIST_ASSERT_VALID(&ProcReadyList));
00123 
00124     /* Sleeping with IRQs disabled or preemption forbidden is illegal */
00125     IRQ_ASSERT_ENABLED();
00126     ASSERT(proc_allowed());
00127 
00128     // Will invoke proc_switch() in interrupt context
00129     kill(0, SIGUSR1);
00130 }
00131 
00132 void proc_yield(void)
00133 {
00134     TRACEMSG("%p:%s", CurrentProcess, proc_currentName());
00135 
00136     IRQ_DISABLE;
00137     SCHED_ENQUEUE(CurrentProcess);
00138     IRQ_ENABLE;
00139 
00140     proc_switch();
00141 }
00142 
00143 void proc_entry(void (*user_entry)(void))
00144 {
00145     user_entry();
00146     proc_exit();
00147 }
00148 
00149 void preempt_init(void)
00150 {
00151     MOD_CHECK(irq);
00152     MOD_CHECK(timer);
00153 
00154     irq_register(SIGUSR1, proc_schedule);
00155 
00156     timer_setSoftint(&preempt_timer, proc_preempt, NULL);
00157     timer_setDelay(&preempt_timer, CONFIG_KERN_QUANTUM);
00158     timer_add(&preempt_timer);
00159 
00160     idle_init();
00161 
00162     MOD_INIT(preempt);
00163 }
00164 
00165 #endif // CONFIG_KERN_PREEMPT