sig_wait(): Don't call proc_shecule() with interrupts disabled
[bertos.git] / bertos / kern / proc.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 1999,2000,2001 Bernie Innocenti <bernie@codewiz.org>
31  *
32  * -->
33  *
34  * \brief Simple realtime multitasking scheduler.
35  *        Context switching is only done cooperatively.
36  *
37  * \version $Id$
38  * \author Bernie Innocenti <bernie@codewiz.org>
39  * \author Stefano Fedrigo <aleph@develer.com>
40  */
41
42 #include "proc_p.h"
43 #include "proc.h"
44
45 #include "cfg/cfg_arch.h"  /* ARCH_EMUL */
46 #include <cfg/debug.h>
47 #include <cfg/module.h>
48
49 // Log settings for cfg/log.h.
50 #define LOG_LEVEL   KERN_LOG_LEVEL
51 #define LOG_FORMAT  KERN_LOG_FORMAT
52 #include <cfg/log.h>
53
54 #include <cpu/irq.h>
55 #include <cpu/types.h>
56 #include <cpu/attr.h>
57
58 #include <mware/event.h>
59
60 #include <string.h>           /* memset() */
61
62 /**
63  * CPU dependent context switching routines.
64  *
65  * Saving and restoring the context on the stack is done by a CPU-dependent
66  * support routine which usually needs to be written in assembly.
67  */
68 EXTERN_C void asm_switch_context(cpustack_t **new_sp, cpustack_t **save_sp);
69
70 /*
71  * The scheduer tracks ready processes by enqueuing them in the
72  * ready list.
73  *
74  * \note Access to the list must occur while interrupts are disabled.
75  */
76 REGISTER List ProcReadyList;
77
78 /*
79  * Holds a pointer to the TCB of the currently running process.
80  *
81  * \note User applications should use proc_current() to retrieve this value.
82  */
83 REGISTER Process *CurrentProcess;
84
85 #if CONFIG_KERN_PREEMPTIVE
86 /*
87  * The time sharing scheduler forces a task switch when the current
88  * process has exhausted its quantum.
89  */
90 uint16_t Quantum;
91 #endif
92
93
94 #if (ARCH & ARCH_EMUL)
95 /*
96  * In hosted environments, we must emulate the stack on the real process stack.
97  *
98  * Access to this list must be protected by PROC_ATOMIC().
99  */
100 extern List StackFreeList;
101 #endif
102
103 /** The main process (the one that executes main()). */
104 struct Process MainProcess;
105
106
107 static void proc_init_struct(Process *proc)
108 {
109         /* Avoid warning for unused argument. */
110         (void)proc;
111
112 #if CONFIG_KERN_SIGNALS
113         proc->sig_recv = 0;
114 #endif
115
116 #if CONFIG_KERN_PREEMPTIVE
117         proc->forbid_cnt = 0;
118 #endif
119
120 #if CONFIG_KERN_HEAP
121         proc->flags = 0;
122 #endif
123 }
124
125 MOD_DEFINE(proc);
126
127 void proc_init(void)
128 {
129         LIST_INIT(&ProcReadyList);
130
131         /*
132          * We "promote" the current context into a real process. The only thing we have
133          * to do is create a PCB and make it current. We don't need to setup the stack
134          * pointer because it will be written the first time we switch to another process.
135          */
136         proc_init_struct(&MainProcess);
137         CurrentProcess = &MainProcess;
138
139 #if CONFIG_KERN_MONITOR
140         monitor_init();
141         monitor_add(CurrentProcess, "main");
142 #endif
143
144         MOD_INIT(proc);
145 }
146
147
148 /**
149  * Create a new process, starting at the provided entry point.
150  *
151  * \return Process structure of new created process
152  *         if successful, NULL otherwise.
153  */
154 struct Process *proc_new_with_name(UNUSED(const char *, name), void (*entry)(void), iptr_t data, size_t stack_size, cpustack_t *stack_base)
155 {
156         Process *proc;
157         size_t i;
158         const size_t PROC_SIZE_WORDS = ROUND2(sizeof(Process), sizeof(cpustack_t)) / sizeof(cpustack_t);
159 #if CONFIG_KERN_HEAP
160         bool free_stack = false;
161 #endif
162         TRACEMSG("name=%s", name);
163
164 #if (ARCH & ARCH_EMUL)
165         /* Ignore stack provided by caller and use the large enough default instead. */
166         PROC_ATOMIC(stack_base = (cpustack_t *)list_remHead(&StackFreeList));
167
168         stack_size = CONFIG_PROC_DEFSTACKSIZE;
169 #elif CONFIG_KERN_HEAP
170         /* Did the caller provide a stack for us? */
171         if (!stack_base)
172         {
173                 /* Did the caller specify the desired stack size? */
174                 if (!stack_size)
175                         stack_size = CONFIG_PROC_DEFSTACKSIZE + sizeof(Process);
176
177                 /* Allocate stack dinamically */
178                 if (!(stack_base = heap_alloc(stack_size)))
179                         return NULL;
180
181                 free_stack = true;
182         }
183 #else
184         /* Stack must have been provided by the user */
185         ASSERT_VALID_PTR(stack_base);
186         ASSERT(stack_size);
187 #endif
188
189 #if CONFIG_KERN_MONITOR
190         /* Fill-in the stack with a special marker to help debugging */
191 #warning size incorrect
192         memset(stack_base, CONFIG_KERN_STACKFILLCODE, stack_size / sizeof(cpustack_t));
193 #endif
194
195         /* Initialize the process control block */
196         if (CPU_STACK_GROWS_UPWARD)
197         {
198                 proc = (Process*)stack_base;
199                 proc->stack = stack_base + PROC_SIZE_WORDS;
200                 if (CPU_SP_ON_EMPTY_SLOT)
201                         proc->stack++;
202         }
203         else
204         {
205                 proc = (Process*)(stack_base + stack_size / sizeof(cpustack_t) - PROC_SIZE_WORDS);
206                 proc->stack = (cpustack_t*)proc;
207                 if (CPU_SP_ON_EMPTY_SLOT)
208                         proc->stack--;
209         }
210
211         proc_init_struct(proc);
212         proc->user_data = data;
213
214 #if CONFIG_KERN_HEAP | CONFIG_KERN_MONITOR | (ARCH & ARCH_EMUL)
215         proc->stack_base = stack_base;
216         proc->stack_size = stack_size;
217         #if CONFIG_KERN_HEAP
218         if (free_stack)
219                 proc->flags |= PF_FREESTACK;
220         #endif
221 #endif
222
223         /* Initialize process stack frame */
224         CPU_PUSH_CALL_CONTEXT(proc->stack, proc_exit);
225         CPU_PUSH_CALL_CONTEXT(proc->stack, entry);
226
227         /* Push a clean set of CPU registers for asm_switch_context() */
228         for (i = 0; i < CPU_SAVED_REGS_CNT; i++)
229                 CPU_PUSH_WORD(proc->stack, CPU_REG_INIT_VALUE(i));
230
231         /* Add to ready list */
232         ATOMIC(SCHED_ENQUEUE(proc));
233         ATOMIC(LIST_ASSERT_VALID(&ProcReadyList));
234
235 #if CONFIG_KERN_MONITOR
236         monitor_add(proc, name);
237 #endif
238
239         return proc;
240 }
241
242 /** Rename a process */
243 void proc_rename(struct Process *proc, const char *name)
244 {
245 #if CONFIG_KERN_MONITOR
246         monitor_rename(proc, name);
247 #else
248         (void)proc; (void)name;
249 #endif
250 }
251
252
253 /**
254  * System scheduler: pass CPU control to the next process in
255  * the ready queue.
256  */
257 void proc_schedule(void)
258 {
259         struct Process *old_process;
260         cpuflags_t flags;
261
262         ATOMIC(LIST_ASSERT_VALID(&ProcReadyList));
263         ASSERT_USER_CONTEXT();
264         ASSERT_IRQ_ENABLED();
265
266         /* Remember old process to save its context later */
267         old_process = CurrentProcess;
268
269         /* Poll on the ready queue for the first ready process */
270         IRQ_SAVE_DISABLE(flags);
271         while (!(CurrentProcess = (struct Process *)list_remHead(&ProcReadyList)))
272         {
273                 /*
274                  * Make sure we physically reenable interrupts here, no matter what
275                  * the current task status is. This is important because if we
276                  * are idle-spinning, we must allow interrupts, otherwise no
277                  * process will ever wake up.
278                  *
279                  * During idle-spinning, an interrupt can occur and it may
280                  * modify \p ProcReadyList. To ensure that compiler reload this
281                  * variable every while cycle we call CPU_MEMORY_BARRIER.
282                  * The memory barrier ensure that all variables used in this context
283                  * are reloaded.
284                  * \todo If there was a way to write sig_wait() so that it does not
285                  * disable interrupts while waiting, there would not be any
286                  * reason to do this.
287                  */
288                 IRQ_ENABLE;
289                 CPU_IDLE;
290                 MEMORY_BARRIER;
291                 IRQ_DISABLE;
292         }
293         IRQ_RESTORE(flags);
294
295         /*
296          * Optimization: don't switch contexts when the active
297          * process has not changed.
298          */
299         if (CurrentProcess != old_process)
300         {
301                 cpustack_t *dummy;
302
303                 #if CONFIG_KERN_MONITOR
304                         LOG_INFO("Switch from %p(%s) to %p(%s)\n",
305                                 old_process,    old_process ? old_process->monitor.name : "NONE",
306                                 CurrentProcess, CurrentProcess->monitor.name);
307                 #endif
308
309                 #if CONFIG_KERN_PREEMPTIVE
310                         /* Reset quantum for this process */
311                         Quantum = CONFIG_KERN_QUANTUM;
312                 #endif
313
314                 /* Save context of old process and switch to new process. If there is no
315                  * old process, we save the old stack pointer into a dummy variable that
316                  * we ignore. In fact, this happens only when the old process has just
317                  * exited.
318                  * TODO: Instead of physically clearing the process at exit time, a zombie
319                  * list should be created.
320                  */
321                 asm_switch_context(&CurrentProcess->stack, old_process ? &old_process->stack : &dummy);
322         }
323
324         /* This RET resumes the execution on the new process */
325 }
326
327
328 /**
329  * Terminate the current process
330  */
331 void proc_exit(void)
332 {
333         TRACE;
334
335 #if CONFIG_KERN_MONITOR
336         monitor_remove(CurrentProcess);
337 #endif
338
339 #if CONFIG_KERN_HEAP
340         /*
341          * The following code is BROKEN.
342          * We are freeing our own stack before entering proc_schedule()
343          * BAJO: A correct fix would be to rearrange the scheduler with
344          *  an additional parameter which frees the old stack/process
345          *  after a context switch.
346          */
347         if (CurrentProcess->flags & PF_FREESTACK)
348                 heap_free(CurrentProcess->stack_base, CurrentProcess->stack_size);
349         heap_free(CurrentProcess);
350 #endif
351
352 #if (ARCH & ARCH_EMUL)
353 #warning This is wrong
354         /* Reinsert process stack in free list */
355         PROC_ATOMIC(ADDHEAD(&StackFreeList, (Node *)(CurrentProcess->stack
356                 - (CONFIG_PROC_DEFSTACKSIZE / sizeof(cpustack_t)))));
357
358         /*
359          * NOTE: At this point the first two words of what used
360          * to be our stack contain a list node. From now on, we
361          * rely on the compiler not reading/writing the stack.
362          */
363 #endif /* ARCH_EMUL */
364
365         CurrentProcess = NULL;
366         proc_schedule();
367         /* not reached */
368 }
369
370
371 /**
372  * Co-operative context switch
373  */
374 void proc_switch(void)
375 {
376         ATOMIC(SCHED_ENQUEUE(CurrentProcess));
377
378         proc_schedule();
379 }
380
381
382 /**
383  * Get the pointer to the current process
384  */
385 struct Process *proc_current(void)
386 {
387         return CurrentProcess;
388 }
389
390 /**
391  * Get the pointer to the user data of the current process
392  */
393 iptr_t proc_current_user_data(void)
394 {
395         return CurrentProcess->user_data;
396 }
397
398
399 #if CONFIG_KERN_PREEMPTIVE
400
401 /**
402  * Disable preemptive task switching.
403  *
404  * The scheduler maintains a per-process nesting counter.  Task switching is
405  * effectively re-enabled only when the number of calls to proc_permit()
406  * matches the number of calls to proc_forbid().
407  *
408  * Calling functions that could sleep while task switching is disabled
409  * is dangerous, although supported.  Preemptive task switching is
410  * resumed while the process is sleeping and disabled again as soon as
411  * it wakes up again.
412  *
413  * \sa proc_permit()
414  */
415 void proc_forbid(void)
416 {
417         /* No need to protect against interrupts here. */
418         ++CurrentProcess->forbid_cnt;
419 }
420
421 /**
422  * Re-enable preemptive task switching.
423  *
424  * \sa proc_forbid()
425  */
426 void proc_permit(void)
427 {
428         /* No need to protect against interrupts here. */
429         --CurrentProcess->forbid_cnt;
430 }
431
432 #endif /* CONFIG_KERN_PREEMPTIVE */