preempt.c

Go to the documentation of this file.
00001 
00087 #include "cfg/cfg_proc.h"
00088 
00089 #include "proc_p.h"
00090 #include "proc.h"
00091 
00092 #include <kern/irq.h>
00093 #include <kern/monitor.h>
00094 #include <cpu/frame.h> // CPU_IDLE
00095 #include <cpu/irq.h>   // IRQ_DISABLE()...
00096 #include <cfg/log.h>
00097 #include <cfg/module.h>
00098 #include <cfg/depend.h>    // CONFIG_DEPEND()
00099 
00100 // Check config dependencies
00101 CONFIG_DEPEND(CONFIG_KERN_PREEMPT, CONFIG_KERN);
00102 
00103 MOD_DEFINE(preempt)
00104 
00105 /* Global preemption nesting counter */
00106 cpu_atomic_t preempt_count;
00107 
00108 /*
00109  * The time sharing interval: when a process is scheduled on a CPU it gets an
00110  * amount of CONFIG_KERN_QUANTUM clock ticks. When these ticks expires and
00111  * preemption is enabled a new process is selected to run.
00112  */
00113 int _proc_quantum;
00114 
00120 void preempt_yield(void);
00121 int preempt_needPreempt(void);
00122 void preempt_preempt(void);
00123 void preempt_switch(void);
00124 void preempt_wakeup(Process *proc);
00125 void preempt_init(void);
00126 
00130 static void preempt_schedule(void)
00131 {
00132     _proc_quantum = CONFIG_KERN_QUANTUM;
00133     proc_schedule();
00134 }
00135 
00139 int preempt_needPreempt(void)
00140 {
00141     if (UNLIKELY(current_process == NULL))
00142         return 0;
00143     if (!proc_preemptAllowed())
00144         return 0;
00145     return _proc_quantum ? prio_next() > prio_curr() :
00146             prio_next() >= prio_curr();
00147 }
00148 
00152 void preempt_preempt(void)
00153 {
00154     IRQ_ASSERT_DISABLED();
00155     ASSERT(current_process);
00156 
00157     /* Perform the kernel preemption */
00158     LOG_INFO("preempting %p:%s\n", current_process, proc_currentName());
00159     /* We are inside a IRQ context, so ATOMIC is not needed here */
00160     SCHED_ENQUEUE(current_process);
00161     preempt_schedule();
00162 }
00163 
00172 void preempt_switch(void)
00173 {
00174     ASSERT(proc_preemptAllowed());
00175 
00176     ATOMIC(preempt_schedule());
00177 }
00178 
00182 void preempt_wakeup(Process *proc)
00183 {
00184     ASSERT(proc_preemptAllowed());
00185     ASSERT(current_process);
00186     IRQ_ASSERT_DISABLED();
00187 
00188     if (prio_proc(proc) >= prio_curr())
00189     {
00190         Process *old_process = current_process;
00191 
00192         SCHED_ENQUEUE(current_process);
00193         _proc_quantum = CONFIG_KERN_QUANTUM;
00194         current_process = proc;
00195         proc_switchTo(current_process, old_process);
00196     }
00197     else
00198         SCHED_ENQUEUE_HEAD(proc);
00199 }
00200 
00204 void preempt_yield(void)
00205 {
00206     /*
00207      * Voluntary preemption while preemption is disabled is considered
00208      * illegal, as not very useful in practice.
00209      *
00210      * ASSERT if it happens.
00211      */
00212     ASSERT(proc_preemptAllowed());
00213     IRQ_ASSERT_ENABLED();
00214 
00215     ATOMIC(
00216         SCHED_ENQUEUE(current_process);
00217         preempt_schedule();
00218     );
00219 }
00220 
00221 void preempt_init(void)
00222 {
00223     MOD_INIT(preempt);
00224 }