Introduce proc_wakeup().
authorarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Thu, 25 Mar 2010 14:56:22 +0000 (14:56 +0000)
committerarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Thu, 25 Mar 2010 14:56:22 +0000 (14:56 +0000)
Add a new primitive in each scheduler to wakeup a process and
immediately dispatch it to the CPU.

git-svn-id: https://src.develer.com/svnoss/bertos/trunk@3268 38d2e660-2303-0410-9eaa-f027e97ec537

bertos/kern/coop.c
bertos/kern/preempt.c
bertos/kern/proc.c
bertos/kern/proc.h
bertos/kern/proc_p.h

index 1b2e1bb9bc42497a193d12e736642f8155b67250..542ed67844a7dc0acddb63196369c68572a50c31 100644 (file)
  */
 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
  */
index f77dd85eff1c632bbd73adf1053b350140cfc1ca..1cb5e5a07f88d61f1989888855d3d8425eadb64c 100644 (file)
@@ -121,6 +121,7 @@ void preempt_yield(void);
 int preempt_needPreempt(void);
 void preempt_preempt(void);
 void preempt_switch(void);
+void preempt_wakeup(Process *proc);
 void preempt_init(void);
 
 /**
@@ -171,11 +172,32 @@ void preempt_preempt(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.
  */
index 623c1d3fb5d87dba4ceb91b5c35ddcd6f85749c8..acaf4220a1bdd3527f274762096b648f65ecac20 100644 (file)
 
 #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.
@@ -428,15 +420,6 @@ void proc_exit(void)
        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.
  */
@@ -470,22 +453,7 @@ void proc_schedule(void)
                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(&current_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());
 }
index 390099da4b771789c5aa55741526f25284163330..bacd052be848fdebf85b826ece98fb527a88ca63 100644 (file)
@@ -148,6 +148,7 @@ void proc_exit(void);
 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.
@@ -167,6 +168,7 @@ INLINE void __proc_noop(void)
         * Preemptive scheduler: private methods.
         */
        #define preempt_switch          proc_switch
+       #define preempt_wakeup          proc_wakeup
 #else
        /**
         * Co-operative scheduler: public methods.
@@ -178,6 +180,7 @@ INLINE void __proc_noop(void)
         * 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);
@@ -191,7 +194,11 @@ const char *proc_currentName(void);
  * 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);
index 27d65fe288193a3a78aa579c370fbb43273f1586..85cb758f9ecfd7472ea540a3547bb2261fa5717b 100644 (file)
 
 #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.
@@ -72,7 +96,8 @@ extern REGISTER List     proc_ready_list;
 #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)
@@ -80,6 +105,7 @@ extern REGISTER List     proc_ready_list;
                        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)
@@ -153,6 +179,9 @@ void proc_switch(void);
 /* 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);