*/
void coop_yield(void);
void coop_switch(void);
+void coop_wakeup(Process *proc);
+/**
+ * Give the control of the CPU to another process.
+ *
+ * \note Assume the current process has been already added to a wait queue.
+ *
+ * \warning This should be considered an internal kernel function, even if it
+ * is allowed, usage from application code is strongly discouraged.
+ */
void coop_switch(void)
{
- IRQ_ASSERT_ENABLED();
-
ATOMIC(proc_schedule());
}
+/**
+ * Immediately wakeup a process, dispatching it to the CPU.
+ */
+void coop_wakeup(Process *proc)
+{
+ ASSERT(proc_preemptAllowed());
+ ASSERT(current_process);
+ IRQ_ASSERT_DISABLED();
+
+ if (prio_proc(proc) >= prio_curr())
+ {
+ Process *old_process = current_process;
+
+ SCHED_ENQUEUE(current_process);
+ current_process = proc;
+ proc_switchTo(current_process, old_process);
+ }
+ else
+ SCHED_ENQUEUE_HEAD(proc);
+}
+
/**
* Co-operative context switch
*/
int preempt_needPreempt(void);
void preempt_preempt(void);
void preempt_switch(void);
+void preempt_wakeup(Process *proc);
void preempt_init(void);
/**
void preempt_switch(void)
{
ASSERT(proc_preemptAllowed());
- IRQ_ASSERT_ENABLED();
ATOMIC(preempt_schedule());
}
+/**
+ * Immediately wakeup a process, dispatching it to the CPU.
+ */
+void preempt_wakeup(Process *proc)
+{
+ ASSERT(proc_preemptAllowed());
+ ASSERT(current_process);
+ IRQ_ASSERT_DISABLED();
+
+ if (prio_proc(proc) >= prio_curr())
+ {
+ Process *old_process = current_process;
+
+ SCHED_ENQUEUE(current_process);
+ _proc_quantum = CONFIG_KERN_QUANTUM;
+ current_process = proc;
+ proc_switchTo(current_process, old_process);
+ }
+ else
+ SCHED_ENQUEUE_HEAD(proc);
+}
+
/**
* Voluntarily release the CPU.
*/
#define PROC_SIZE_WORDS (ROUND_UP2(sizeof(Process), sizeof(cpu_stack_t)) / sizeof(cpu_stack_t))
-/**
- * CPU dependent context switching routines.
- *
- * Saving and restoring the context on the stack is done by a CPU-dependent
- * support routine which usually needs to be written in assembly.
- */
-EXTERN_C void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **save_sp);
-
/*
* The scheduer tracks ready processes by enqueuing them in the
* ready list.
ASSERT(0);
}
-
-/**
- * Get the pointer to the user data of the current process
- */
-iptr_t proc_currentUserData(void)
-{
- return current_process->user_data;
-}
-
/**
* Call the scheduler and eventually replace the current running process.
*/
MEMORY_BARRIER;
IRQ_DISABLE;
}
- /*
- * Optimization: don't switch contexts when the active process has not
- * changed.
- */
- if (LIKELY(current_process != old_process)) {
- cpu_stack_t *dummy;
-
- /*
- * Save context of old process and switch to new process. If
- * there is no old process, we save the old stack pointer into
- * a dummy variable that we ignore. In fact, this happens only
- * when the old process has just exited.
- */
- asm_switch_context(¤t_process->stack,
- old_process ? &old_process->stack : &dummy);
- }
+ proc_switchTo(current_process, old_process);
/* This RET resumes the execution on the new process */
LOG_INFO("resuming %p:%s\n", current_process, proc_currentName());
}
void proc_yield(void);
void proc_preempt(void);
int proc_needPreempt(void);
+void proc_wakeup(Process *proc);
/**
* Dummy function that defines unimplemented scheduler class methods.
* Preemptive scheduler: private methods.
*/
#define preempt_switch proc_switch
+ #define preempt_wakeup proc_wakeup
#else
/**
* Co-operative scheduler: public methods.
* Co-operative scheduler: private methods.
*/
#define coop_switch proc_switch
+ #define coop_wakeup proc_wakeup
#endif
void proc_rename(struct Process *proc, const char *name);
* the returned pointer to the correct type.
* \return Pointer to the user data of the current process.
*/
-iptr_t proc_currentUserData(void);
+INLINE iptr_t proc_currentUserData(void)
+{
+ extern struct Process *current_process;
+ return current_process->user_data;
+}
int proc_testSetup(void);
int proc_testRun(void);
#include <kern/proc.h> // struct Process
+/**
+ * CPU dependent context switching routines.
+ *
+ * Saving and restoring the context on the stack is done by a CPU-dependent
+ * support routine which usually needs to be written in assembly.
+ */
+EXTERN_C void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **save_sp);
+
+/*
+ * Save context of old process and switch to new process.
+ */
+INLINE void proc_switchTo(Process *next, Process *prev)
+{
+ cpu_stack_t *dummy;
+
+ if (UNLIKELY(next == prev))
+ return;
+ /*
+ * If there is no old process, we save the old stack pointer into a
+ * dummy variable that we ignore. In fact, this happens only when the
+ * old process has just exited.
+ */
+ asm_switch_context(&next->stack, prev ? &prev->stack : &dummy);
+}
/**
* \name Flags for Process.flags.
#if CONFIG_KERN_PRI
#define prio_next() (LIST_EMPTY(&proc_ready_list) ? INT_MIN : \
((PriNode *)LIST_HEAD(&proc_ready_list))->pri)
- #define prio_curr() (current_process->link.pri)
+ #define prio_proc(proc) (proc->link.pri)
+ #define prio_curr() prio_proc(current_process)
#define SCHED_ENQUEUE_INTERNAL(proc) \
LIST_ENQUEUE(&proc_ready_list, &(proc)->link)
LIST_ENQUEUE_HEAD(&proc_ready_list, &(proc)->link)
#else
#define prio_next() 0
+ #define prio_proc(proc) 0
#define prio_curr() 0
#define SCHED_ENQUEUE_INTERNAL(proc) ADDTAIL(&proc_ready_list, &(proc)->link)
/* Low level scheduling routine. */
void proc_schedule(void);
+/* Low level context switch routine. */
+void proc_switchTo(Process *next, Process *prev);
+
/* Initialize a scheduler class. */
void proc_schedInit(void);