X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fkern%2Fproc.c;h=623c1d3fb5d87dba4ceb91b5c35ddcd6f85749c8;hb=d9d931610bca1df6ceb9227eacc9ff2c7f89b77a;hp=794918a54447f1f4a85dcfc78d1c6119ba729cc8;hpb=32d1445272120a254d77ce8d1af1f527da7a2c17;p=bertos.git diff --git a/bertos/kern/proc.c b/bertos/kern/proc.c index 794918a5..623c1d3f 100644 --- a/bertos/kern/proc.c +++ b/bertos/kern/proc.c @@ -60,6 +60,16 @@ #include /* memset() */ +#define PROC_SIZE_WORDS (ROUND_UP2(sizeof(Process), sizeof(cpu_stack_t)) / sizeof(cpu_stack_t)) + +/** + * CPU dependent context switching routines. + * + * Saving and restoring the context on the stack is done by a CPU-dependent + * support routine which usually needs to be written in assembly. + */ +EXTERN_C void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **save_sp); + /* * The scheduer tracks ready processes by enqueuing them in the * ready list. @@ -83,7 +93,7 @@ static struct Process main_process; /** * Local heap dedicated to allocate the memory used by the processes. */ -static HEAP_DEFINE_BUF(heap_buf, KERN_MINSTACKSIZE * 128); +static HEAP_DEFINE_BUF(heap_buf, CONFIG_KERN_HEAP_SIZE); static Heap proc_heap; /* @@ -137,11 +147,6 @@ void proc_init(void) monitor_init(); monitor_add(current_process, "main"); #endif - -#if CONFIG_KERN_PREEMPT - preempt_init(); -#endif - MOD_INIT(proc); } @@ -163,8 +168,10 @@ static void proc_freeZombies(void) return; if (proc->flags & PF_FREESTACK) + { PROC_ATOMIC(heap_freemem(&proc_heap, proc->stack_base, - proc->stack_size)); + proc->stack_size + PROC_SIZE_WORDS * sizeof(cpu_stack_t))); + } } } @@ -206,7 +213,6 @@ static void proc_addZombie(Process *proc) 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) { Process *proc; - const size_t PROC_SIZE_WORDS = ROUND_UP2(sizeof(Process), sizeof(cpu_stack_t)) / sizeof(cpu_stack_t); LOG_INFO("name=%s", name); #if CONFIG_KERN_HEAP bool free_stack = false; @@ -430,3 +436,56 @@ iptr_t proc_currentUserData(void) { return current_process->user_data; } + +/** + * Call the scheduler and eventually replace the current running process. + */ +void proc_schedule(void) +{ + Process *old_process = current_process; + + IRQ_ASSERT_DISABLED(); + + /* Poll on the ready queue for the first ready process */ + LIST_ASSERT_VALID(&proc_ready_list); + while (!(current_process = (struct Process *)list_remHead(&proc_ready_list))) + { + /* + * Make sure we physically reenable interrupts here, no matter what + * the current task status is. This is important because if we + * are idle-spinning, we must allow interrupts, otherwise no + * process will ever wake up. + * + * During idle-spinning, an interrupt can occur and it may + * modify \p proc_ready_list. To ensure that compiler reload this + * variable every while cycle we call CPU_MEMORY_BARRIER. + * The memory barrier ensure that all variables used in this context + * are reloaded. + * \todo If there was a way to write sig_wait() so that it does not + * disable interrupts while waiting, there would not be any + * reason to do this. + */ + IRQ_ENABLE; + CPU_IDLE; + MEMORY_BARRIER; + IRQ_DISABLE; + } + /* + * Optimization: don't switch contexts when the active process has not + * changed. + */ + if (LIKELY(current_process != old_process)) { + cpu_stack_t *dummy; + + /* + * Save context of old process and switch to new process. If + * there is no old process, we save the old stack pointer into + * a dummy variable that we ignore. In fact, this happens only + * when the old process has just exited. + */ + asm_switch_context(¤t_process->stack, + old_process ? &old_process->stack : &dummy); + } + /* This RET resumes the execution on the new process */ + LOG_INFO("resuming %p:%s\n", current_process, proc_currentName()); +}