proc.h

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