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
00197 # if CONFIG_KERN_PRI_INHERIT
00198 proc->orig_pri = proc->inh_link.pri = proc->link.pri;
00199 proc->inh_blocked_by = NULL;
00200 LIST_INIT(&proc->inh_list);
00201 # endif
00202 #endif
00203 }
00204
00205 MOD_DEFINE(proc);
00206
00207 void proc_init(void)
00208 {
00209 LIST_INIT(&proc_ready_list);
00210
00211 #if CONFIG_KERN_HEAP
00212 LIST_INIT(&zombie_list);
00213 heap_init(&proc_heap, heap_buf, sizeof(heap_buf));
00214 #endif
00215
00216
00217
00218
00219
00220 proc_initStruct(&main_process);
00221 current_process = &main_process;
00222
00223 #if CONFIG_KERN_MONITOR
00224 monitor_init();
00225 monitor_add(current_process, "main");
00226 #endif
00227 MOD_INIT(proc);
00228 }
00229
00230
00231 #if CONFIG_KERN_HEAP
00232
00237 static void proc_freeZombies(void)
00238 {
00239 Process *proc;
00240
00241 while (1)
00242 {
00243 PROC_ATOMIC(proc = (Process *)list_remHead(&zombie_list));
00244 if (proc == NULL)
00245 return;
00246
00247 if (proc->flags & PF_FREESTACK)
00248 {
00249 PROC_ATOMIC(heap_freemem(&proc_heap, proc->stack_base,
00250 proc->stack_size + PROC_SIZE_WORDS * sizeof(cpu_stack_t)));
00251 }
00252 }
00253 }
00254
00258 static void proc_addZombie(Process *proc)
00259 {
00260 Node *node;
00261 #if CONFIG_KERN_PREEMPT
00262 ASSERT(!proc_preemptAllowed());
00263 #endif
00264
00265 #if CONFIG_KERN_PRI
00266 node = &(proc)->link.link;
00267 #else
00268 node = &(proc)->link;
00269 #endif
00270 LIST_ASSERT_VALID(&zombie_list);
00271 ADDTAIL(&zombie_list, node);
00272 }
00273
00274 #endif
00275
00290 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)
00291 {
00292 Process *proc;
00293 LOG_INFO("name=%s", name);
00294 #if CONFIG_KERN_HEAP
00295 bool free_stack = false;
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 proc_freeZombies();
00312
00313
00314 if (!stack_base)
00315 {
00316
00317 if (!stack_size)
00318 stack_size = KERN_MINSTACKSIZE;
00319
00320
00321 PROC_ATOMIC(stack_base =
00322 (cpu_stack_t *)heap_allocmem(&proc_heap, stack_size));
00323 if (stack_base == NULL)
00324 return NULL;
00325
00326 free_stack = true;
00327 }
00328
00329 #else // CONFIG_KERN_HEAP
00330
00331
00332 ASSERT2(IS_VALID_PTR(stack_base), "Invalid stack pointer. Did you forget to \
00333 enable CONFIG_KERN_HEAP?");
00334 ASSERT2(stack_size, "Stack size cannot be 0.");
00335
00336 #endif // CONFIG_KERN_HEAP
00337
00338 #if CONFIG_KERN_MONITOR
00339
00340
00341
00342
00343
00344
00345 memset(stack_base, (int)CONFIG_KERN_STACKFILLCODE, stack_size);
00346 #endif
00347
00348
00349 if (CPU_STACK_GROWS_UPWARD)
00350 {
00351 proc = (Process *)stack_base;
00352 proc->stack = stack_base + PROC_SIZE_WORDS;
00353
00354 proc->stack = (cpu_stack_t *)((uintptr_t)proc->stack + (sizeof(cpu_aligned_stack_t) - ((uintptr_t)proc->stack % sizeof(cpu_aligned_stack_t))));
00355 if (CPU_SP_ON_EMPTY_SLOT)
00356 proc->stack++;
00357 }
00358 else
00359 {
00360 proc = (Process *)(stack_base + stack_size / sizeof(cpu_stack_t) - PROC_SIZE_WORDS);
00361
00362 proc->stack = (cpu_stack_t *)((uintptr_t)proc - ((uintptr_t)proc % sizeof(cpu_aligned_stack_t)));
00363 if (CPU_SP_ON_EMPTY_SLOT)
00364 proc->stack--;
00365 }
00366
00367 ASSERT((uintptr_t)proc->stack % sizeof(cpu_aligned_stack_t) == 0);
00368
00369 stack_size -= PROC_SIZE_WORDS * sizeof(cpu_stack_t);
00370 proc_initStruct(proc);
00371 proc->user_data = data;
00372
00373 #if CONFIG_KERN_HEAP | CONFIG_KERN_MONITOR
00374 proc->stack_base = stack_base;
00375 proc->stack_size = stack_size;
00376 #if CONFIG_KERN_HEAP
00377 if (free_stack)
00378 proc->flags |= PF_FREESTACK;
00379 #endif
00380 #endif
00381 proc->user_entry = entry;
00382 CPU_CREATE_NEW_STACK(proc->stack);
00383
00384 #if CONFIG_KERN_MONITOR
00385 monitor_add(proc, name);
00386 #endif
00387
00388
00389 ATOMIC(SCHED_ENQUEUE(proc));
00390
00391 return proc;
00392 }
00393
00399 const char *proc_name(struct Process *proc)
00400 {
00401 #if CONFIG_KERN_MONITOR
00402 return proc ? proc->monitor.name : "<NULL>";
00403 #else
00404 (void)proc;
00405 return "---";
00406 #endif
00407 }
00408
00410 const char *proc_currentName(void)
00411 {
00412 return proc_name(proc_current());
00413 }
00414
00416 void proc_rename(struct Process *proc, const char *name)
00417 {
00418 #if CONFIG_KERN_MONITOR
00419 monitor_rename(proc, name);
00420 #else
00421 (void)proc; (void)name;
00422 #endif
00423 }
00424
00425
00426 #if CONFIG_KERN_PRI
00427
00446 void proc_setPri(struct Process *proc, int pri)
00447 {
00448 #if CONFIG_KERN_PRI_INHERIT
00449 int new_pri;
00450
00451
00452
00453
00454
00455
00456 proc->orig_pri = pri;
00457
00458
00459 if ((new_pri = __prio_proc(proc)) == proc->link.pri)
00460 return;
00461
00462
00463
00464
00465
00466
00467
00468 proc->link.pri = new_pri;
00469 #else
00470 if (proc->link.pri == pri)
00471 return;
00472
00473 proc->link.pri = pri;
00474 #endif // CONFIG_KERN_PRI_INHERIT
00475
00476 if (proc != current_process)
00477 ATOMIC(sched_reenqueue(proc));
00478 }
00479 #endif // CONFIG_KERN_PRI
00480
00481 INLINE void proc_run(void)
00482 {
00483 void (*entry)(void) = current_process->user_entry;
00484
00485 LOG_INFO("New process starting at %p", entry);
00486 entry();
00487 }
00488
00492 void proc_entry(void)
00493 {
00494
00495
00496
00497
00498 IRQ_ENABLE;
00499
00500 proc_run();
00501 proc_exit();
00502 }
00503
00507 void proc_exit(void)
00508 {
00509 LOG_INFO("%p:%s", current_process, proc_currentName());
00510
00511 #if CONFIG_KERN_MONITOR
00512 monitor_remove(current_process);
00513 #endif
00514
00515 proc_forbid();
00516 #if CONFIG_KERN_HEAP
00517
00518
00519
00520
00521 proc_addZombie(current_process);
00522 #endif
00523 current_process = NULL;
00524 proc_permit();
00525
00526 proc_switch();
00527
00528
00529 ASSERT(0);
00530 }
00531
00535 static void proc_schedule(void)
00536 {
00537 Process *old_process = current_process;
00538
00539 IRQ_ASSERT_DISABLED();
00540
00541
00542 LIST_ASSERT_VALID(&proc_ready_list);
00543 while (!(current_process = (struct Process *)list_remHead(&proc_ready_list)))
00544 {
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 IRQ_ENABLE;
00561 CPU_IDLE;
00562 MEMORY_BARRIER;
00563 IRQ_DISABLE;
00564 }
00565 if (CONTEXT_SWITCH_FROM_ISR())
00566 proc_context_switch(current_process, old_process);
00567
00568 LOG_INFO("resuming %p:%s\n", current_process, proc_currentName());
00569 }
00570
00571 #if CONFIG_KERN_PREEMPT
00572
00573 cpu_atomic_t preempt_count;
00574
00575
00576
00577
00578
00579
00580 int _proc_quantum;
00581
00585 bool proc_needPreempt(void)
00586 {
00587 if (UNLIKELY(current_process == NULL))
00588 return false;
00589 if (!proc_preemptAllowed())
00590 return false;
00591 if (LIST_EMPTY(&proc_ready_list))
00592 return false;
00593 return preempt_quantum() ? prio_next() > prio_curr() :
00594 prio_next() >= prio_curr();
00595 }
00596
00600 void proc_preempt(void)
00601 {
00602 IRQ_ASSERT_DISABLED();
00603 ASSERT(current_process);
00604
00605
00606 LOG_INFO("preempting %p:%s\n", current_process, proc_currentName());
00607
00608 SCHED_ENQUEUE(current_process);
00609 preempt_reset_quantum();
00610 proc_schedule();
00611 }
00612 #endif
00613
00614
00615 static void proc_switchTo(Process *proc)
00616 {
00617 Process *old_process = current_process;
00618
00619 SCHED_ENQUEUE(current_process);
00620 preempt_reset_quantum();
00621 current_process = proc;
00622 proc_context_switch(current_process, old_process);
00623 }
00624
00633 void proc_switch(void)
00634 {
00635 ASSERT(proc_preemptAllowed());
00636 ATOMIC(
00637 preempt_reset_quantum();
00638 proc_schedule();
00639 );
00640 }
00641
00645 void proc_wakeup(Process *proc)
00646 {
00647 ASSERT(proc_preemptAllowed());
00648 ASSERT(current_process);
00649 IRQ_ASSERT_DISABLED();
00650
00651 if (prio_proc(proc) >= prio_curr())
00652 proc_switchTo(proc);
00653 else
00654 SCHED_ENQUEUE_HEAD(proc);
00655 }
00656
00660 void proc_yield(void)
00661 {
00662 Process *proc;
00663
00664
00665
00666
00667
00668
00669
00670 ASSERT(proc_preemptAllowed());
00671 IRQ_ASSERT_ENABLED();
00672
00673 IRQ_DISABLE;
00674 proc = (struct Process *)list_remHead(&proc_ready_list);
00675 if (proc)
00676 proc_switchTo(proc);
00677 IRQ_ENABLE;
00678 }