proc.c

Go to the documentation of this file.
00001 
00040 #include "proc_p.h"
00041 #include "proc.h"
00042 
00043 #include "cfg/cfg_proc.h"
00044 #define LOG_LEVEL KERN_LOG_LEVEL
00045 #define LOG_FORMAT KERN_LOG_FORMAT
00046 #include <cfg/log.h>
00047 
00048 #include "cfg/cfg_arch.h"  // ARCH_EMUL
00049 #include "cfg/cfg_monitor.h"
00050 #include <cfg/macros.h>    // ROUND_UP2
00051 #include <cfg/module.h>
00052 #include <cfg/depend.h>    // CONFIG_DEPEND()
00053 
00054 #include <cpu/irq.h>
00055 #include <cpu/types.h>
00056 #include <cpu/attr.h>
00057 #include <cpu/frame.h>
00058 
00059 #if CONFIG_KERN_HEAP
00060     #include <struct/heap.h>
00061 #endif
00062 
00063 #include <string.h>           /* memset() */
00064 
00065 /*
00066  * The scheduer tracks ready processes by enqueuing them in the
00067  * ready list.
00068  *
00069  * \note Access to the list must occur while interrupts are disabled.
00070  */
00071 REGISTER List ProcReadyList;
00072 
00073 /*
00074  * Holds a pointer to the TCB of the currently running process.
00075  *
00076  * \note User applications should use proc_current() to retrieve this value.
00077  */
00078 REGISTER Process *CurrentProcess;
00079 
00080 #if (ARCH & ARCH_EMUL)
00081 /*
00082  * In some hosted environments, we must emulate the stack on the real
00083  * process stack to satisfy consistency checks in system libraries and
00084  * because some ABIs place trampolines on the stack.
00085  *
00086  * Access to this list must be protected by PROC_ATOMIC().
00087  */
00088 List StackFreeList;
00089 
00090 #define NPROC 10
00091 cpu_stack_t proc_stacks[NPROC][(64 * 1024) / sizeof(cpu_stack_t)];
00092 #endif
00093 
00095 struct Process MainProcess;
00096 
00097 
00098 static void proc_init_struct(Process *proc)
00099 {
00100     /* Avoid warning for unused argument. */
00101     (void)proc;
00102 
00103 #if CONFIG_KERN_SIGNALS
00104     proc->sig_recv = 0;
00105     proc->sig_wait = 0;
00106 #endif
00107 
00108 #if CONFIG_KERN_HEAP
00109     proc->flags = 0;
00110 #endif
00111 
00112 #if CONFIG_KERN_PRI
00113     proc->link.pri = 0;
00114 #endif
00115 
00116 }
00117 
00118 MOD_DEFINE(proc);
00119 
00120 void proc_init(void)
00121 {
00122     LIST_INIT(&ProcReadyList);
00123 
00124 #if ARCH & ARCH_EMUL
00125     LIST_INIT(&StackFreeList);
00126     for (int i = 0; i < NPROC; i++)
00127         ADDTAIL(&StackFreeList, (Node *)proc_stacks[i]);
00128 #endif
00129 
00130     /*
00131      * We "promote" the current context into a real process. The only thing we have
00132      * to do is create a PCB and make it current. We don't need to setup the stack
00133      * pointer because it will be written the first time we switch to another process.
00134      */
00135     proc_init_struct(&MainProcess);
00136     CurrentProcess = &MainProcess;
00137 
00138 #if CONFIG_KERN_MONITOR
00139     monitor_init();
00140     monitor_add(CurrentProcess, "main");
00141 #endif
00142 
00143 #if CONFIG_KERN_PREEMPT
00144     preempt_init();
00145 #endif
00146 
00147     MOD_INIT(proc);
00148 }
00149 
00164 struct Process *proc_new_with_name(UNUSED_ARG(const char *, name), void (*entry)(void), iptr_t data, size_t stack_size, cpu_stack_t *stack_base)
00165 {
00166     Process *proc;
00167     const size_t PROC_SIZE_WORDS = ROUND_UP2(sizeof(Process), sizeof(cpu_stack_t)) / sizeof(cpu_stack_t);
00168 #if CONFIG_KERN_HEAP
00169     bool free_stack = false;
00170 #endif
00171     LOG_INFO("name=%s", name);
00172 
00173 #if (ARCH & ARCH_EMUL)
00174     /* Ignore stack provided by caller and use the large enough default instead. */
00175     PROC_ATOMIC(stack_base = (cpu_stack_t *)list_remHead(&StackFreeList));
00176     ASSERT(stack_base);
00177 
00178     stack_size = KERN_MINSTACKSIZE;
00179 #elif CONFIG_KERN_HEAP
00180     /* Did the caller provide a stack for us? */
00181     if (!stack_base)
00182     {
00183         /* Did the caller specify the desired stack size? */
00184         if (!stack_size)
00185             stack_size = KERN_MINSTACKSIZE;
00186 
00187         /* Allocate stack dinamically */
00188         if (!(stack_base = heap_alloc(stack_size)))
00189             return NULL;
00190 
00191         free_stack = true;
00192     }
00193 
00194 #else // !ARCH_EMUL && !CONFIG_KERN_HEAP
00195 
00196     /* Stack must have been provided by the user */
00197     ASSERT_VALID_PTR(stack_base);
00198     ASSERT(stack_size);
00199 
00200 #endif // !ARCH_EMUL && !CONFIG_KERN_HEAP
00201 
00202 #if CONFIG_KERN_MONITOR
00203     /*
00204      * Fill-in the stack with a special marker to help debugging.
00205      * On 64bit platforms, CONFIG_KERN_STACKFILLCODE is larger
00206      * than an int, so the (int) cast is required to silence the
00207      * warning for truncating its size.
00208      */
00209     memset(stack_base, (int)CONFIG_KERN_STACKFILLCODE, stack_size);
00210 #endif
00211 
00212     /* Initialize the process control block */
00213     if (CPU_STACK_GROWS_UPWARD)
00214     {
00215         proc = (Process *)stack_base;
00216         proc->stack = stack_base + PROC_SIZE_WORDS;
00217         // On some architecture stack should be aligned, so we do it.
00218         proc->stack = (cpu_stack_t *)((uintptr_t)proc->stack + (sizeof(cpu_aligned_stack_t) - ((uintptr_t)proc->stack % sizeof(cpu_aligned_stack_t))));
00219         if (CPU_SP_ON_EMPTY_SLOT)
00220             proc->stack++;
00221     }
00222     else
00223     {
00224         proc = (Process *)(stack_base + stack_size / sizeof(cpu_stack_t) - PROC_SIZE_WORDS);
00225         // On some architecture stack should be aligned, so we do it.
00226         proc->stack = (cpu_stack_t *)((uintptr_t)proc - ((uintptr_t)proc % sizeof(cpu_aligned_stack_t)));
00227         if (CPU_SP_ON_EMPTY_SLOT)
00228             proc->stack--;
00229     }
00230     /* Ensure stack is aligned */
00231     ASSERT((uintptr_t)proc->stack % sizeof(cpu_aligned_stack_t) == 0);
00232 
00233     stack_size -= PROC_SIZE_WORDS * sizeof(cpu_stack_t);
00234     proc_init_struct(proc);
00235     proc->user_data = data;
00236 
00237 #if CONFIG_KERN_HEAP | CONFIG_KERN_MONITOR | (ARCH & ARCH_EMUL)
00238     proc->stack_base = stack_base;
00239     proc->stack_size = stack_size;
00240     #if CONFIG_KERN_HEAP
00241     if (free_stack)
00242         proc->flags |= PF_FREESTACK;
00243     #endif
00244 #endif
00245 
00246     #if CONFIG_KERN_PREEMPT
00247 
00248         getcontext(&proc->context);
00249         proc->context.uc_stack.ss_sp = proc->stack;
00250         proc->context.uc_stack.ss_size = stack_size - 1;
00251         proc->context.uc_link = NULL;
00252         makecontext(&proc->context, (void (*)(void))proc_entry, 1, entry);
00253 
00254     #else // !CONFIG_KERN_PREEMPT
00255     
00256         CPU_CREATE_NEW_STACK(proc->stack, entry, proc_exit);
00257         
00258     #endif // CONFIG_KERN_PREEMPT
00259 
00260     #if CONFIG_KERN_MONITOR
00261         monitor_add(proc, name);
00262     #endif
00263 
00264     /* Add to ready list */
00265     ATOMIC(SCHED_ENQUEUE(proc));
00266 
00267     return proc;
00268 }
00269 
00275 const char *proc_name(struct Process *proc)
00276 {
00277     #if CONFIG_KERN_MONITOR
00278         return proc ? proc->monitor.name : "<NULL>";
00279     #else
00280         (void)proc;
00281         return "---";
00282     #endif
00283 }
00284 
00286 const char *proc_currentName(void)
00287 {
00288     return proc_name(proc_current());
00289 }
00290 
00292 void proc_rename(struct Process *proc, const char *name)
00293 {
00294 #if CONFIG_KERN_MONITOR
00295     monitor_rename(proc, name);
00296 #else
00297     (void)proc; (void)name;
00298 #endif
00299 }
00300 
00301 
00302 #if CONFIG_KERN_PRI
00303 
00322 void proc_setPri(struct Process *proc, int pri)
00323 {
00324         if (proc->link.pri == pri)
00325             return;
00326 
00327         proc->link.pri = pri;
00328 
00329         if (proc != CurrentProcess)
00330         {
00331                 proc_forbid();
00332                 ATOMIC(sched_reenqueue(proc));
00333                 proc_permit();
00334         }
00335 }
00336 #endif // CONFIG_KERN_PRI
00337 
00341 void proc_exit(void)
00342 {
00343     LOG_INFO("%p:%s", CurrentProcess, proc_currentName());
00344 
00345 #if CONFIG_KERN_MONITOR
00346     monitor_remove(CurrentProcess);
00347 #endif
00348 
00349 #if CONFIG_KERN_HEAP
00350     /*
00351      * The following code is BROKEN.
00352      * We are freeing our own stack before entering proc_schedule()
00353      * BAJO: A correct fix would be to rearrange the scheduler with
00354      *  an additional parameter which frees the old stack/process
00355      *  after a context switch.
00356      */
00357     if (CurrentProcess->flags & PF_FREESTACK)
00358         heap_free(CurrentProcess->stack_base, CurrentProcess->stack_size);
00359     heap_free(CurrentProcess);
00360 #endif
00361 
00362 #if (ARCH & ARCH_EMUL)
00363     /* Reinsert process stack in free list */
00364     PROC_ATOMIC(ADDHEAD(&StackFreeList, (Node *)CurrentProcess->stack_base));
00365 
00366     /*
00367      * NOTE: At this point the first two words of what used
00368      * to be our stack contain a list node. From now on, we
00369      * rely on the compiler not reading/writing the stack.
00370      */
00371 #endif /* ARCH_EMUL */
00372 
00373     CurrentProcess = NULL;
00374     proc_switch();
00375     /* not reached */
00376 }
00377 
00378 
00382 iptr_t proc_currentUserData(void)
00383 {
00384     return CurrentProcess->user_data;
00385 }