proc.h

Go to the documentation of this file.
00001 
00044 #ifndef KERN_PROC_H
00045 #define KERN_PROC_H
00046 
00047 #include "cfg/cfg_proc.h"
00048 #include "cfg/cfg_monitor.h"
00049 
00050 #include <cfg/compiler.h>
00051 
00052 #if CONFIG_KERN_PREEMPT
00053     #include <cfg/debug.h> // ASSERT()
00054 #endif
00055 
00056 #include <cpu/types.h> // cpu_stack_t
00057 #include <cpu/frame.h> // CPU_SAVED_REGS_CNT
00058 
00059 /*
00060  * Forward declaration. The definition of struct Process is private to the
00061  * scheduler and hidden in proc_p.h.
00062  */
00063 struct Process;
00064 
00065 void proc_init(void);
00066 struct Process *proc_new_with_name(const char *name, void (*entry)(void), iptr_t data, size_t stacksize, cpu_stack_t *stack);
00067 
00068 #if !CONFIG_KERN_MONITOR
00069     #define proc_new(entry,data,size,stack) proc_new_with_name(NULL,(entry),(data),(size),(stack))
00070 #else
00071     #define proc_new(entry,data,size,stack) proc_new_with_name(#entry,(entry),(data),(size),(stack))
00072 #endif
00073 
00074 void proc_exit(void);
00075 void proc_yield(void);
00076 void proc_rename(struct Process *proc, const char *name);
00077 const char *proc_name(struct Process *proc);
00078 const char *proc_currentName(void);
00079 iptr_t proc_currentUserData(void);
00080 
00081 int proc_testSetup(void);
00082 int proc_testRun(void);
00083 int proc_testTearDown(void);
00084 
00092 INLINE struct Process *proc_current(void)
00093 {
00094     extern struct Process *CurrentProcess;
00095     return CurrentProcess;
00096 }
00097 
00098 #if CONFIG_KERN_PRI
00099     void proc_setPri(struct Process *proc, int pri);
00100 #else
00101     INLINE void proc_setPri(UNUSED_ARG(struct Process *,proc), UNUSED_ARG(int, pri))
00102     {
00103     }
00104 #endif
00105 
00126 INLINE void proc_forbid(void)
00127 {
00128     #if CONFIG_KERN_PREEMPT
00129         extern cpu_atomic_t _preempt_forbid_cnt;
00130         /*
00131          * We don't need to protect the counter against other processes.
00132          * The reason why is a bit subtle.
00133          *
00134          * If a process gets here, preempt_forbid_cnt can be either 0,
00135          * or != 0.  In the latter case, preemption is already disabled
00136          * and no concurrency issues can occur.
00137          *
00138          * In the former case, we could be preempted just after reading the
00139          * value 0 from memory, and a concurrent process might, in fact,
00140          * bump the value of preempt_forbid_cnt under our nose!
00141          *
00142          * BUT: if this ever happens, then we won't get another chance to
00143          * run until the other process calls proc_permit() to re-enable
00144          * preemption.  At this point, the value of preempt_forbid_cnt
00145          * must be back to 0, and thus what we had originally read from
00146          * memory happens to be valid.
00147          *
00148          * No matter how hard you think about it, and how complicated you
00149          * make your scenario, the above holds true as long as
00150          * "preempt_forbid_cnt != 0" means that no task switching is
00151          * possible.
00152          */
00153         ++_preempt_forbid_cnt;
00154 
00155         /*
00156          * Make sure _preempt_forbid_cnt is flushed to memory so the
00157          * preemption softirq will see the correct value from now on.
00158          */
00159         MEMORY_BARRIER;
00160     #endif
00161 }
00162 
00168 INLINE void proc_permit(void)
00169 {
00170     #if CONFIG_KERN_PREEMPT
00171 
00172         /*
00173          * This is to ensure any global state changed by the process gets
00174          * flushed to memory before task switching is re-enabled.
00175          */
00176         MEMORY_BARRIER;
00177         extern cpu_atomic_t _preempt_forbid_cnt;
00178         /* No need to protect against interrupts here. */
00179         ASSERT(_preempt_forbid_cnt != 0);
00180         --_preempt_forbid_cnt;
00181 
00182         /*
00183          * This ensures _preempt_forbid_cnt is flushed to memory immediately
00184          * so the preemption interrupt sees the correct value.
00185          */
00186         MEMORY_BARRIER;
00187 
00188     #endif
00189 }
00190 
00196 INLINE bool proc_allowed(void)
00197 {
00198     #if CONFIG_KERN_PREEMPT
00199         extern cpu_atomic_t _preempt_forbid_cnt;
00200         return (_preempt_forbid_cnt == 0);
00201     #else
00202         return true;
00203     #endif
00204 }
00205 
00209 #define PROC_ATOMIC(CODE) \
00210     do { \
00211         proc_forbid(); \
00212         CODE; \
00213         proc_permit(); \
00214     } while(0)
00215 
00216 #ifndef CONFIG_KERN_MINSTACKSIZE
00217 
00218     #if (ARCH & ARCH_EMUL)
00219         /* We need a large stack because system libraries are bloated */
00220         #define CONFIG_KERN_MINSTACKSIZE  65536
00221     #else
00222 
00241         #define CONFIG_KERN_MINSTACKSIZE  \
00242             (CPU_SAVED_REGS_CNT * 2 * sizeof(cpu_stack_t) \
00243             + 48 * sizeof(int))
00244     #endif
00245 #endif
00246 
00247 /* Memory fill codes to help debugging */
00248 #if CONFIG_KERN_MONITOR
00249     #include <cpu/types.h>
00250     #if (SIZEOF_CPUSTACK_T == 1)
00251         /* 8bit cpu_stack_t */
00252         #define CONFIG_KERN_STACKFILLCODE  0xA5
00253         #define CONFIG_KERN_MEMFILLCODE    0xDB
00254     #elif (SIZEOF_CPUSTACK_T == 2)
00255         /* 16bit cpu_stack_t */
00256         #define CONFIG_KERN_STACKFILLCODE  0xA5A5
00257         #define CONFIG_KERN_MEMFILLCODE    0xDBDB
00258     #elif (SIZEOF_CPUSTACK_T == 4)
00259         /* 32bit cpu_stack_t */
00260         #define CONFIG_KERN_STACKFILLCODE  0xA5A5A5A5UL
00261         #define CONFIG_KERN_MEMFILLCODE    0xDBDBDBDBUL
00262     #elif (SIZEOF_CPUSTACK_T == 8)
00263         /* 64bit cpu_stack_t */
00264         #define CONFIG_KERN_STACKFILLCODE  0xA5A5A5A5A5A5A5A5ULL
00265         #define CONFIG_KERN_MEMFILLCODE    0xDBDBDBDBDBDBDBDBULL
00266     #else
00267         #error No cpu_stack_t size supported!
00268     #endif
00269 #endif
00270 
00271 #endif /* KERN_PROC_H */