Rename myself
[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  *
39  * \author Bernie Innocenti <bernie@codewiz.org>
40  * \author Stefano Fedrigo <aleph@develer.com>
41  */
42
43
44 #include "proc_p.h"
45 #include "proc.h"
46
47 #include "cfg/cfg_arch.h"  /* ARCH_EMUL */
48 #include <cfg/debug.h>
49 #include <cfg/module.h>
50 #include <cfg/macros.h>       /* ABS() */
51
52 #include <cpu/irq.h>
53 #include <cpu/types.h>
54 #include <cpu/attr.h>
55
56 #include <mware/event.h>
57
58 #include <string.h>           /* memset() */
59
60 /**
61  * CPU dependent context switching routines.
62  *
63  * \note This function *MUST* preserve also the status of the interrupts.
64  */
65 EXTERN_C void asm_switch_context(cpustack_t **new_sp, cpustack_t **save_sp);
66 EXTERN_C int asm_switch_version(void);
67
68 /*
69  * The scheduer tracks ready and waiting processes
70  * by enqueuing them in these lists. A pointer to the currently
71  * running process is stored in the CurrentProcess pointer.
72  *
73  * NOTE: these variables are protected by DI/EI locking
74  */
75 REGISTER Process *CurrentProcess;
76 REGISTER List     ProcReadyList;
77
78
79 #if CONFIG_KERN_PREEMPTIVE
80 /*
81  * The time sharing scheduler forces a task switch when
82  * the current process has consumed its quantum.
83  */
84 uint16_t Quantum;
85 #endif
86
87
88 /* In Win32 we must emulate stack on the real process stack */
89 #if (ARCH & ARCH_EMUL)
90 extern List StackFreeList;
91 #endif
92
93 /** The main process (the one that executes main()). */
94 struct Process MainProcess;
95
96
97 static void proc_init_struct(Process *proc)
98 {
99         /* Avoid warning for unused argument. */
100         (void)proc;
101
102 #if CONFIG_KERN_SIGNALS
103         proc->sig_recv = 0;
104 #endif
105
106 #if CONFIG_KERN_PREEMPTIVE
107         proc->forbid_cnt = 0;
108 #endif
109
110 #if CONFIG_KERN_HEAP
111         proc->flags = 0;
112 #endif
113 }
114
115 MOD_DEFINE(proc);
116
117 void proc_init(void)
118 {
119         LIST_INIT(&ProcReadyList);
120
121 #if CONFIG_KERN_MONITOR
122         monitor_init();
123 #endif
124
125         /* We "promote" the current context into a real process. The only thing we have
126          * to do is create a PCB and make it current. We don't need to setup the stack
127          * pointer because it will be written the first time we switch to another process.
128          */
129         proc_init_struct(&MainProcess);
130         CurrentProcess = &MainProcess;
131
132         /* Make sure the assembly routine is up-to-date with us */
133         ASSERT(asm_switch_version() == 1);
134         MOD_INIT(proc);
135 }
136
137
138 /**
139  * Create a new process, starting at the provided entry point.
140  *
141  * \return Process structure of new created process
142  *         if successful, NULL otherwise.
143  */
144 struct Process *proc_new_with_name(UNUSED(const char *, name), void (*entry)(void), iptr_t data, size_t stacksize, cpustack_t *stack_base)
145 {
146         Process *proc;
147         size_t i;
148         size_t proc_size_words = ROUND2(sizeof(Process), sizeof(cpustack_t)) / sizeof(cpustack_t);
149 #if CONFIG_KERN_HEAP
150         bool free_stack = false;
151 #endif
152
153 #if (ARCH & ARCH_EMUL)
154         /* Ignore stack provided by caller and use the large enough default instead. */
155         stack_base = (cpustack_t *)list_remHead(&StackFreeList);
156
157         stacksize = CONFIG_PROC_DEFSTACKSIZE;
158 #elif CONFIG_KERN_HEAP
159         /* Did the caller provide a stack for us? */
160         if (!stack_base)
161         {
162                 /* Did the caller specify the desired stack size? */
163                 if (!stacksize)
164                         stacksize = CONFIG_PROC_DEFSTACKSIZE + sizeof(Process);
165
166                 /* Allocate stack dinamically */
167                 if (!(stack_base = heap_alloc(stacksize)))
168                         return NULL;
169
170                 free_stack = true;
171         }
172 #else
173         /* Stack must have been provided by the user */
174         ASSERT(stack_base);
175         ASSERT(stacksize);
176 #endif
177
178 #if CONFIG_KERN_MONITOR
179         /* Fill-in the stack with a special marker to help debugging */
180         memset(stack_base, CONFIG_KERN_STACKFILLCODE, stacksize / sizeof(cpustack_t));
181 #endif
182
183         /* Initialize the process control block */
184         if (CPU_STACK_GROWS_UPWARD)
185         {
186                 proc = (Process*)stack_base;
187                 proc->stack = stack_base + proc_size_words;
188                 if (CPU_SP_ON_EMPTY_SLOT)
189                         proc->stack++;
190         }
191         else
192         {
193                 proc = (Process*)(stack_base + stacksize / sizeof(cpustack_t) - proc_size_words);
194                 proc->stack = (cpustack_t*)proc;
195                 if (CPU_SP_ON_EMPTY_SLOT)
196                         proc->stack--;
197         }
198
199         proc_init_struct(proc);
200         proc->user_data = data;
201
202 #if CONFIG_KERN_HEAP
203         proc->stack_base = stack_base;
204         proc->stack_size = stack_size;
205         if (free_stack)
206                 proc->flags |= PF_FREESTACK;
207 #endif
208
209         /* Initialize process stack frame */
210         CPU_PUSH_CALL_CONTEXT(proc->stack, proc_exit);
211         CPU_PUSH_CALL_CONTEXT(proc->stack, entry);
212
213         /* Push a clean set of CPU registers for asm_switch_context() */
214         for (i = 0; i < CPU_SAVED_REGS_CNT; i++)
215                 CPU_PUSH_WORD(proc->stack, CPU_REG_INIT_VALUE(i));
216
217         /* Add to ready list */
218         ATOMIC(SCHED_ENQUEUE(proc));
219
220 #if CONFIG_KERN_MONITOR
221         monitor_add(proc, name, stack_base, stacksize);
222 #endif
223
224         return proc;
225 }
226
227 /** Rename a process */
228 void proc_rename(struct Process *proc, const char *name)
229 {
230 #if CONFIG_KERN_MONITOR
231         monitor_rename(proc, name);
232 #else
233         (void)proc; (void)name;
234 #endif
235 }
236
237
238 /**
239  * System scheduler: pass CPU control to the next process in
240  * the ready queue.
241  *
242  * Saving and restoring the context on the stack is done
243  * by a CPU-dependent support routine which must usually be
244  * written in assembly.
245  */
246 void proc_schedule(void)
247 {
248         struct Process *old_process;
249         cpuflags_t flags;
250
251         /* Remember old process to save its context later */
252         old_process = CurrentProcess;
253
254 #ifdef IRQ_RUNNING
255         /* Scheduling in interrupts is a nono. */
256         ASSERT(!IRQ_RUNNING());
257 #endif
258
259         /* Poll on the ready queue for the first ready process */
260         IRQ_SAVE_DISABLE(flags);
261         while (!(CurrentProcess = (struct Process *)list_remHead(&ProcReadyList)))
262         {
263                 /*
264                  * Make sure we physically reenable interrupts here, no matter what
265                  * the current task status is. This is important because if we
266                  * are idle-spinning, we must allow interrupts, otherwise no
267                  * process will ever wake up.
268                  *
269                  * During idle-spinning, an interrupt can occur and it may
270                  * modify \p ProcReadyList. To ensure that compiler reload this
271                  * variable every while cycle we call CPU_MEMORY_BARRIER.
272                  * The memory barrier ensure that all variables used in this context
273                  * are reloaded.
274                  * \todo If there was a way to write sig_wait() so that it does not
275                  * disable interrupts while waiting, there would not be any
276                  * reason to do this.
277                  */
278                 IRQ_ENABLE;
279                 CPU_IDLE;
280                 MEMORY_BARRIER;
281                 IRQ_DISABLE;
282         }
283         IRQ_RESTORE(flags);
284
285         /*
286          * Optimization: don't switch contexts when the active
287          * process has not changed.
288          */
289         if (CurrentProcess != old_process)
290         {
291                 cpustack_t *dummy;
292
293 #if CONFIG_KERN_PREEMPTIVE
294                 /* Reset quantum for this process */
295                 Quantum = CONFIG_KERN_QUANTUM;
296 #endif
297
298                 /* Save context of old process and switch to new process. If there is no
299                  * old process, we save the old stack pointer into a dummy variable that
300                  * we ignore. In fact, this happens only when the old process has just
301                  * exited.
302                  * TODO: Instead of physically clearing the process at exit time, a zombie
303                  * list should be created.
304                  */
305                 asm_switch_context(&CurrentProcess->stack, old_process ? &old_process->stack : &dummy);
306         }
307
308         /* This RET resumes the execution on the new process */
309 }
310
311
312 /**
313  * Terminate the current process
314  */
315 void proc_exit(void)
316 {
317 #if CONFIG_KERN_MONITOR
318         monitor_remove(CurrentProcess);
319 #endif
320
321 #if CONFIG_KERN_HEAP
322         /*
323          * The following code is BROKEN.
324          * We are freeing our own stack before entering proc_schedule()
325          * BAJO: A correct fix would be to rearrange the scheduler with
326          *  an additional parameter which frees the old stack/process
327          *  after a context switch.
328          */
329         if (CurrentProcess->flags & PF_FREESTACK)
330                 heap_free(CurrentProcess->stack_base, CurrentProcess->stack_size);
331         heap_free(CurrentProcess);
332 #endif
333
334 #if (ARCH & ARCH_EMUL)
335 #warning This is wrong
336         /* Reinsert process stack in free list */
337         ADDHEAD(&StackFreeList, (Node *)(CurrentProcess->stack
338                 - (CONFIG_PROC_DEFSTACKSIZE / sizeof(cpustack_t))));
339
340         /*
341          * NOTE: At this point the first two words of what used
342          * to be our stack contain a list node. From now on, we
343          * rely on the compiler not reading/writing the stack.
344          */
345 #endif /* ARCH_EMUL */
346
347         CurrentProcess = NULL;
348         proc_schedule();
349         /* not reached */
350 }
351
352
353 /**
354  * Co-operative context switch
355  */
356 void proc_switch(void)
357 {
358         cpuflags_t flags;
359
360         IRQ_SAVE_DISABLE(flags);
361         SCHED_ENQUEUE(CurrentProcess);
362         IRQ_RESTORE(flags);
363
364         proc_schedule();
365 }
366
367
368 /**
369  * Get the pointer to the current process
370  */
371 struct Process *proc_current(void)
372 {
373         return CurrentProcess;
374 }
375
376 /**
377  * Get the pointer to the user data of the current process
378  */
379 iptr_t proc_current_user_data(void)
380 {
381         return CurrentProcess->user_data;
382 }
383
384
385 #if CONFIG_KERN_PREEMPTIVE
386
387 /**
388  * Disable preemptive task switching.
389  *
390  * The scheduler maintains a per-process nesting counter.  Task switching is
391  * effectively re-enabled only when the number of calls to proc_permit()
392  * matches the number of calls to proc_forbid().
393  *
394  * Calling functions that could sleep while task switching is disabled
395  * is dangerous, although supported.  Preemptive task switching is
396  * resumed while the process is sleeping and disabled again as soon as
397  * it wakes up again.
398  *
399  * \sa proc_permit()
400  */
401 void proc_forbid(void)
402 {
403         /* No need to protect against interrupts here. */
404         ++CurrentProcess->forbid_cnt;
405 }
406
407 /**
408  * Re-enable preemptive task switching.
409  *
410  * \sa proc_forbid()
411  */
412 void proc_permit(void)
413 {
414         /* No need to protect against interrupts here. */
415         --CurrentProcess->forbid_cnt;
416 }
417
418 #endif /* CONFIG_KERN_PREEMPTIVE */