proc.c
Go to the documentation of this file.00001
00088 #include "proc_p.h"
00089 #include "proc.h"
00090
00091 #include "cfg/cfg_proc.h"
00092 #define LOG_LEVEL KERN_LOG_LEVEL
00093 #define LOG_FORMAT KERN_LOG_FORMAT
00094 #include <cfg/log.h>
00095
00096 #include "cfg/cfg_monitor.h"
00097 #include <cfg/macros.h>
00098 #include <cfg/module.h>
00099 #include <cfg/depend.h>
00100
00101 #include <cpu/irq.h>
00102 #include <cpu/types.h>
00103 #include <cpu/attr.h>
00104 #include <cpu/frame.h>
00105
00106 #if CONFIG_KERN_HEAP
00107 #include <struct/heap.h>
00108 #endif
00109
00110 #include <string.h>
00111
00112 #define PROC_SIZE_WORDS (ROUND_UP2(sizeof(Process), sizeof(cpu_stack_t)) / sizeof(cpu_stack_t))
00113
00114
00115
00116
00117
00118
00119
00120 REGISTER List proc_ready_list;
00121
00122
00123
00124
00125
00126
00127 REGISTER Process *current_process;
00128
00130 static struct Process main_process;
00131
00132 #if CONFIG_KERN_HEAP
00133
00137 static HEAP_DEFINE_BUF(heap_buf, CONFIG_KERN_HEAP_SIZE);
00138 static Heap proc_heap;
00139
00140
00141
00142
00143
00144
00145
00146 static List zombie_list;
00147
00148 #endif
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 #define CONTEXT_SWITCH_FROM_ISR() (!IRQ_RUNNING())
00162
00163
00164
00165
00166 static void proc_context_switch(Process *next, Process *prev)
00167 {
00168 cpu_stack_t *dummy;
00169
00170 if (UNLIKELY(next == prev))
00171 return;
00172
00173
00174
00175
00176
00177 asm_switch_context(&next->stack, prev ? &prev->stack : &dummy);
00178 }
00179
00180 static void proc_initStruct(Process *proc)
00181 {
00182
00183 (void)proc;
00184
00185 #if CONFIG_KERN_SIGNALS
00186 proc->sig_recv = 0;
00187 proc->sig_wait = 0;
00188 #endif
00189
00190 #if CONFIG_KERN_HEAP
00191 proc->flags = 0;
00192 #endif
00193
00194 #if CONFIG_KERN_PRI
00195 proc->link.pri = 0;
00196 #endif
00197 }
00198
00199 MOD_DEFINE(proc);
00200
00201 void proc_init(void)
00202 {
00203 LIST_INIT(&proc_ready_list);
00204
00205 #if CONFIG_KERN_HEAP
00206 LIST_INIT(&zombie_list);
00207 heap_init(&proc_heap, heap_buf, sizeof(heap_buf));
00208 #endif
00209
00210
00211
00212
00213
00214 proc_initStruct(&main_process);
00215 current_process = &main_process;
00216
00217 #if CONFIG_KERN_MONITOR
00218 monitor_init();
00219 monitor_add(current_process, "main");
00220 #endif
00221 MOD_INIT(proc);
00222 }
00223
00224
00225 #if CONFIG_KERN_HEAP
00226
00231 static void proc_freeZombies(void)
00232 {
00233 Process *proc;
00234
00235 while (1)
00236 {
00237 PROC_ATOMIC(proc = (Process *)list_remHead(&zombie_list));
00238 if (proc == NULL)
00239 return;
00240
00241 if (proc->flags & PF_FREESTACK)
00242 {
00243 PROC_ATOMIC(heap_freemem(&proc_heap, proc->stack_base,
00244 proc->stack_size + PROC_SIZE_WORDS * sizeof(cpu_stack_t)));
00245 }
00246 }
00247 }
00248
00252 static void proc_addZombie(Process *proc)
00253 {
00254 Node *node;
00255 #if CONFIG_KERN_PREEMPT
00256 ASSERT(!proc_preemptAllowed());
00257 #endif
00258
00259 #if CONFIG_KERN_PRI
00260 node = &(proc)->link.link;
00261 #else
00262 node = &(proc)->link;
00263 #endif
00264 LIST_ASSERT_VALID(&zombie_list);
00265 ADDTAIL(&zombie_list, node);
00266 }
00267
00268 #endif
00269
00284 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)
00285 {
00286 Process *proc;
00287 LOG_INFO("name=%s", name);
00288 #if CONFIG_KERN_HEAP
00289 bool free_stack = false;
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 proc_freeZombies();
00306
00307
00308 if (!stack_base)
00309 {
00310
00311 if (!stack_size)
00312 stack_size = KERN_MINSTACKSIZE;
00313
00314
00315 PROC_ATOMIC(stack_base =
00316 (cpu_stack_t *)heap_allocmem(&proc_heap, stack_size));
00317 if (stack_base == NULL)
00318 return NULL;
00319
00320 free_stack = true;
00321 }
00322
00323 #else // CONFIG_KERN_HEAP
00324
00325
00326 ASSERT_VALID_PTR(stack_base);
00327 ASSERT(stack_size);
00328
00329 #endif // CONFIG_KERN_HEAP
00330
00331 #if CONFIG_KERN_MONITOR
00332
00333
00334
00335
00336
00337
00338 memset(stack_base, (int)CONFIG_KERN_STACKFILLCODE, stack_size);
00339 #endif
00340
00341
00342 if (CPU_STACK_GROWS_UPWARD)
00343 {
00344 proc = (Process *)stack_base;
00345 proc->stack = stack_base + PROC_SIZE_WORDS;
00346
00347 proc->stack = (cpu_stack_t *)((uintptr_t)proc->stack + (sizeof(cpu_aligned_stack_t) - ((uintptr_t)proc->stack % sizeof(cpu_aligned_stack_t))));
00348 if (CPU_SP_ON_EMPTY_SLOT)
00349 proc->stack++;
00350 }
00351 else
00352 {
00353 proc = (Process *)(stack_base + stack_size / sizeof(cpu_stack_t) - PROC_SIZE_WORDS);
00354
00355 proc->stack = (cpu_stack_t *)((uintptr_t)proc - ((uintptr_t)proc % sizeof(cpu_aligned_stack_t)));
00356 if (CPU_SP_ON_EMPTY_SLOT)
00357 proc->stack--;
00358 }
00359
00360 ASSERT((uintptr_t)proc->stack % sizeof(cpu_aligned_stack_t) == 0);
00361
00362 stack_size -= PROC_SIZE_WORDS * sizeof(cpu_stack_t);
00363 proc_initStruct(proc);
00364 proc->user_data = data;
00365
00366 #if CONFIG_KERN_HEAP | CONFIG_KERN_MONITOR
00367 proc->stack_base = stack_base;
00368 proc->stack_size = stack_size;
00369 #if CONFIG_KERN_HEAP
00370 if (free_stack)
00371 proc->flags |= PF_FREESTACK;
00372 #endif
00373 #endif
00374 proc->user_entry = entry;
00375 CPU_CREATE_NEW_STACK(proc->stack);
00376
00377 #if CONFIG_KERN_MONITOR
00378 monitor_add(proc, name);
00379 #endif
00380
00381
00382 ATOMIC(SCHED_ENQUEUE(proc));
00383
00384 return proc;
00385 }
00386
00392 const char *proc_name(struct Process *proc)
00393 {
00394 #if CONFIG_KERN_MONITOR
00395 return proc ? proc->monitor.name : "<NULL>";
00396 #else
00397 (void)proc;
00398 return "---";
00399 #endif
00400 }
00401
00403 const char *proc_currentName(void)
00404 {
00405 return proc_name(proc_current());
00406 }
00407
00409 void proc_rename(struct Process *proc, const char *name)
00410 {
00411 #if CONFIG_KERN_MONITOR
00412 monitor_rename(proc, name);
00413 #else
00414 (void)proc; (void)name;
00415 #endif
00416 }
00417
00418
00419 #if CONFIG_KERN_PRI
00420
00439 void proc_setPri(struct Process *proc, int pri)
00440 {
00441 if (proc->link.pri == pri)
00442 return;
00443
00444 proc->link.pri = pri;
00445
00446 if (proc != current_process)
00447 ATOMIC(sched_reenqueue(proc));
00448 }
00449 #endif // CONFIG_KERN_PRI
00450
00451 INLINE void proc_run(void)
00452 {
00453 void (*entry)(void) = current_process->user_entry;
00454
00455 LOG_INFO("New process starting at %p", entry);
00456 entry();
00457 }
00458
00462 void proc_entry(void)
00463 {
00464
00465
00466
00467
00468 IRQ_ENABLE;
00469
00470 proc_run();
00471 proc_exit();
00472 }
00473
00477 void proc_exit(void)
00478 {
00479 LOG_INFO("%p:%s", current_process, proc_currentName());
00480
00481 #if CONFIG_KERN_MONITOR
00482 monitor_remove(current_process);
00483 #endif
00484
00485 proc_forbid();
00486 #if CONFIG_KERN_HEAP
00487
00488
00489
00490
00491 proc_addZombie(current_process);
00492 #endif
00493 current_process = NULL;
00494 proc_permit();
00495
00496 proc_switch();
00497
00498
00499 ASSERT(0);
00500 }
00501
00505 static void proc_schedule(void)
00506 {
00507 Process *old_process = current_process;
00508
00509 IRQ_ASSERT_DISABLED();
00510
00511
00512 LIST_ASSERT_VALID(&proc_ready_list);
00513 while (!(current_process = (struct Process *)list_remHead(&proc_ready_list)))
00514 {
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 IRQ_ENABLE;
00531 CPU_IDLE;
00532 MEMORY_BARRIER;
00533 IRQ_DISABLE;
00534 }
00535 if (CONTEXT_SWITCH_FROM_ISR())
00536 proc_context_switch(current_process, old_process);
00537
00538 LOG_INFO("resuming %p:%s\n", current_process, proc_currentName());
00539 }
00540
00541 #if CONFIG_KERN_PREEMPT
00542
00543 cpu_atomic_t preempt_count;
00544
00545
00546
00547
00548
00549
00550 int _proc_quantum;
00551
00555 bool proc_needPreempt(void)
00556 {
00557 if (UNLIKELY(current_process == NULL))
00558 return false;
00559 if (!proc_preemptAllowed())
00560 return false;
00561 if (LIST_EMPTY(&proc_ready_list))
00562 return false;
00563 return preempt_quantum() ? prio_next() > prio_curr() :
00564 prio_next() >= prio_curr();
00565 }
00566
00570 void proc_preempt(void)
00571 {
00572 IRQ_ASSERT_DISABLED();
00573 ASSERT(current_process);
00574
00575
00576 LOG_INFO("preempting %p:%s\n", current_process, proc_currentName());
00577
00578 SCHED_ENQUEUE(current_process);
00579 preempt_reset_quantum();
00580 proc_schedule();
00581 }
00582 #endif
00583
00584
00585 static void proc_switchTo(Process *proc)
00586 {
00587 Process *old_process = current_process;
00588
00589 SCHED_ENQUEUE(current_process);
00590 preempt_reset_quantum();
00591 current_process = proc;
00592 proc_context_switch(current_process, old_process);
00593 }
00594
00603 void proc_switch(void)
00604 {
00605 ASSERT(proc_preemptAllowed());
00606 ATOMIC(
00607 preempt_reset_quantum();
00608 proc_schedule();
00609 );
00610 }
00611
00615 void proc_wakeup(Process *proc)
00616 {
00617 ASSERT(proc_preemptAllowed());
00618 ASSERT(current_process);
00619 IRQ_ASSERT_DISABLED();
00620
00621 if (prio_proc(proc) >= prio_curr())
00622 proc_switchTo(proc);
00623 else
00624 SCHED_ENQUEUE_HEAD(proc);
00625 }
00626
00630 void proc_yield(void)
00631 {
00632 Process *proc;
00633
00634
00635
00636
00637
00638
00639
00640 ASSERT(proc_preemptAllowed());
00641 IRQ_ASSERT_ENABLED();
00642
00643 IRQ_DISABLE;
00644 proc = (struct Process *)list_remHead(&proc_ready_list);
00645 if (proc)
00646 proc_switchTo(proc);
00647 IRQ_ENABLE;
00648 }