Convert to new Doxygen style.
[bertos.git] / kern / proc.c
1 /**
2  * \file
3  * <!--
4  * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
6  * This file is part of DevLib - See README.devlib for information.
7  * -->
8  *
9  * \brief Simple realtime multitasking scheduler.
10  *        Context switching is only done cooperatively.
11  *
12  * \version $Id$
13  *
14  * \author Bernardo Innocenti <bernie@develer.com>
15  * \author Stefano Fedrigo <aleph@develer.com>
16  */
17
18 /*#*
19  *#* $Log$
20  *#* Revision 1.31  2006/07/19 12:56:27  bernie
21  *#* Convert to new Doxygen style.
22  *#*
23  *#* Revision 1.30  2006/03/27 04:49:23  bernie
24  *#* CPU_IDLE(): Fix for new emulator.
25  *#*
26  *#* Revision 1.29  2006/02/24 01:17:05  bernie
27  *#* Update for new emulator.
28  *#*
29  *#* Revision 1.28  2006/02/21 16:06:55  bernie
30  *#* Cleanup/update process scheduling.
31  *#*
32  *#* Revision 1.27  2005/11/04 16:20:02  bernie
33  *#* Fix reference to README.devlib in header.
34  *#*
35  *#* Revision 1.26  2005/04/11 19:10:28  bernie
36  *#* Include top-level headers from cfg/ subdir.
37  *#*
38  *#* Revision 1.25  2005/03/15 00:20:54  bernie
39  *#* proc_schedule(): New sanity check.
40  *#*
41  *#* Revision 1.24  2005/01/08 09:20:54  bernie
42  *#* Remove unused variable.
43  *#*
44  *#* Revision 1.23  2004/12/13 12:07:06  bernie
45  *#* DISABLE_IRQSAVE/ENABLE_IRQRESTORE: Convert to IRQ_SAVE_DISABLE/IRQ_RESTORE.
46  *#*
47  *#* Revision 1.22  2004/12/13 11:51:08  bernie
48  *#* DISABLE_INTS/ENABLE_INTS: Convert to IRQ_DISABLE/IRQ_ENABLE.
49  *#*
50  *#* Revision 1.21  2004/11/28 23:20:25  bernie
51  *#* Remove obsolete INITLIST macro.
52  *#*
53  *#* Revision 1.20  2004/11/16 22:37:14  bernie
54  *#* Replace IPTR with iptr_t.
55  *#*
56  *#* Revision 1.19  2004/10/19 11:47:39  bernie
57  *#* Kill warnings when !CONFIG_PROC_MONITOR.
58  *#*
59  *#* Revision 1.18  2004/10/19 08:54:43  bernie
60  *#* Initialize forbid_cnt; Formatting/comments fixes.
61  *#*
62  *#* Revision 1.17  2004/10/19 08:47:13  bernie
63  *#* proc_rename(), proc_forbid(), proc_permit(): New functions.
64  *#*
65  *#* Revision 1.16  2004/10/03 20:39:28  bernie
66  *#* Import changes from sc/firmware.
67  *#*
68  *#* Revision 1.15  2004/09/20 03:29:39  bernie
69  *#* C++ fixes.
70  *#*
71  *#* Revision 1.14  2004/09/14 21:06:44  bernie
72  *#* Use debug.h instead of kdebug.h.
73  *#*
74  *#* Revision 1.13  2004/08/29 21:58:53  bernie
75  *#* Include macros.h explicityl.
76  *#*
77  *#* Revision 1.11  2004/08/24 16:09:08  bernie
78  *#* Add missing header.
79  *#*
80  *#* Revision 1.10  2004/08/24 16:07:01  bernie
81  *#* Use kputs()/kputchar() when possible.
82  *#*
83  *#* Revision 1.9  2004/08/24 14:26:57  bernie
84  *#* monitor_debug_stacks(): Conditionally compile on CONFIG_KERN_MONITOR.
85  *#*
86  *#* Revision 1.8  2004/08/14 19:37:57  rasky
87  *#* Merge da SC: macros.h, pool.h, BIT_CHANGE, nome dei processi, etc.
88  *#*
89  *#* Revision 1.7  2004/08/02 20:20:29  aleph
90  *#* Merge from project_ks
91  *#*
92  *#* Revision 1.6  2004/07/30 14:24:16  rasky
93  *#* Task switching con salvataggio perfetto stato di interrupt (SR)
94  *#* Kernel monitor per dump informazioni su stack dei processi
95  *#*
96  *#* Revision 1.5  2004/07/14 14:18:09  rasky
97  *#* Merge da SC: Rimosso timer dentro il task, che รจ uno spreco di memoria per troppi task
98  *#*
99  *#* Revision 1.4  2004/07/13 19:21:28  aleph
100  *#* Avoid warning for unused arg when compiled without some CONFIG_KERN_xx options
101  *#*
102  *#* Revision 1.3  2004/06/06 18:37:57  bernie
103  *#* Rename event macros to look like regular functions.
104  *#*
105  *#* Revision 1.2  2004/06/03 11:27:09  bernie
106  *#* Add dual-license information.
107  *#*
108  *#* Revision 1.1  2004/05/23 17:27:00  bernie
109  *#* Import kern/ subdirectory.
110  *#*
111  *#*/
112
113 #include "proc_p.h"
114 #include "proc.h"
115 //#include "hw.h"
116 #include <mware/event.h>
117 #include <cfg/cpu.h>
118 #include <cfg/debug.h>
119 #include <cfg/arch_config.h>  /* ARCH_EMUL */
120 #include <cfg/macros.h>  /* ABS() */
121
122 #include <string.h> /* memset() */
123
124 /**
125  * CPU dependent context switching routines.
126  *
127  * \note This function *MUST* preserve also the status of the interrupts.
128  */
129 EXTERN_C void asm_switch_context(cpustack_t **new_sp, cpustack_t **save_sp);
130 EXTERN_C int asm_switch_version(void);
131
132 /*
133  * The scheduer tracks ready and waiting processes
134  * by enqueuing them in these lists. A pointer to the currently
135  * running process is stored in the CurrentProcess pointer.
136  *
137  * NOTE: these variables are protected by DI/EI locking
138  */
139 REGISTER Process *CurrentProcess;
140 REGISTER List     ProcReadyList;
141
142
143 #if CONFIG_KERN_PREEMPTIVE
144 /*
145  * The time sharing scheduler forces a task switch when
146  * the current process has consumed its quantum.
147  */
148 uint16_t Quantum;
149 #endif
150
151
152 /* In Win32 we must emulate stack on the real process stack */
153 #if (ARCH & ARCH_EMUL)
154 extern List StackFreeList;
155 #endif
156
157 /** The main process (the one that executes main()). */
158 struct Process MainProcess;
159
160
161 static void proc_init_struct(Process *proc)
162 {
163         /* Avoid warning for unused argument. */
164         (void)proc;
165
166 #if CONFIG_KERN_SIGNALS
167         proc->sig_recv = 0;
168 #endif
169
170 #if CONFIG_KERN_PREEMPTIVE
171         proc->forbid_cnt = 0;
172 #endif
173
174 #if CONFIG_KERN_HEAP
175         proc->flags = 0;
176 #endif
177 }
178
179
180 void proc_init(void)
181 {
182         LIST_INIT(&ProcReadyList);
183
184 #if CONFIG_KERN_MONITOR
185         monitor_init();
186 #endif
187
188         /* We "promote" the current context into a real process. The only thing we have
189          * to do is create a PCB and make it current. We don't need to setup the stack
190          * pointer because it will be written the first time we switch to another process.
191          */
192         proc_init_struct(&MainProcess);
193         CurrentProcess = &MainProcess;
194
195         /* Make sure the assembly routine is up-to-date with us */
196         ASSERT(asm_switch_version() == 1);
197 }
198
199
200 /**
201  * Create a new process, starting at the provided entry point.
202  *
203  * \return Process structure of new created process
204  *         if successful, NULL otherwise.
205  */
206 struct Process *proc_new_with_name(UNUSED(const char *, name), void (*entry)(void), iptr_t data, size_t stacksize, cpustack_t *stack_base)
207 {
208         Process *proc;
209         size_t i;
210         size_t proc_size_words = ROUND2(sizeof(Process), sizeof(cpustack_t)) / sizeof(cpustack_t);
211 #if CONFIG_KERN_HEAP
212         bool free_stack = false;
213 #endif
214
215 #if (ARCH & ARCH_EMUL)
216         /* Ignore stack provided by caller and use the large enough default instead. */
217         stack_base = (cpustack_t *)LIST_HEAD(&StackFreeList);
218         REMOVE(LIST_HEAD(&StackFreeList));
219         stacksize = CONFIG_KERN_DEFSTACKSIZE;
220 #elif CONFIG_KERN_HEAP
221         /* Did the caller provide a stack for us? */
222         if (!stack_base)
223         {
224                 /* Did the caller specify the desired stack size? */
225                 if (!stacksize)
226                         stacksize = CONFIG_KERN_DEFSTACKSIZE + sizeof(Process);
227
228                 /* Allocate stack dinamically */
229                 if (!(stack_base = heap_alloc(stacksize)))
230                         return NULL;
231
232                 free_stack = true;
233         }
234 #else
235         /* Stack must have been provided by the user */
236         ASSERT(stack_base);
237         ASSERT(stacksize);
238 #endif
239
240 #if CONFIG_KERN_MONITOR
241         /* Fill-in the stack with a special marker to help debugging */
242         memset(stack_base, CONFIG_KERN_STACKFILLCODE, stacksize / sizeof(cpustack_t));
243 #endif
244
245         /* Initialize the process control block */
246         if (CPU_STACK_GROWS_UPWARD)
247         {
248                 proc = (Process*)stack_base;
249                 proc->stack = stack_base + proc_size_words;
250                 if (CPU_SP_ON_EMPTY_SLOT)
251                         proc->stack++;
252         }
253         else
254         {
255                 proc = (Process*)(stack_base + stacksize / sizeof(cpustack_t) - proc_size_words);
256                 proc->stack = (cpustack_t*)proc;
257                 if (CPU_SP_ON_EMPTY_SLOT)
258                         proc->stack--;
259         }
260
261         proc_init_struct(proc);
262         proc->user_data = data;
263
264 #if CONFIG_KERN_HEAP
265         proc->stack_base = stack_base;
266         proc->stack_size = stack_size;
267         if (free_stack)
268                 proc->flags |= PF_FREESTACK;
269 #endif
270
271         /* Initialize process stack frame */
272         CPU_PUSH_CALL_CONTEXT(proc->stack, proc_exit);
273         CPU_PUSH_CALL_CONTEXT(proc->stack, entry);
274
275         /* Push a clean set of CPU registers for asm_switch_context() */
276         for (i = 0; i < CPU_SAVED_REGS_CNT; i++)
277                 CPU_PUSH_WORD(proc->stack, CPU_REG_INIT_VALUE(i));
278
279         /* Add to ready list */
280         ATOMIC(SCHED_ENQUEUE(proc));
281
282 #if CONFIG_KERN_MONITOR
283         monitor_add(proc, name, stack_base, stacksize);
284 #endif
285
286         return proc;
287 }
288
289 /** Rename a process */
290 void proc_rename(struct Process *proc, const char *name)
291 {
292 #if CONFIG_KERN_MONITOR
293         monitor_rename(proc, name);
294 #else
295         (void)proc; (void)name;
296 #endif
297 }
298
299
300 /**
301  * System scheduler: pass CPU control to the next process in
302  * the ready queue.
303  *
304  * Saving and restoring the context on the stack is done
305  * by a CPU-dependent support routine which must usually be
306  * written in assembly.
307  */
308 void proc_schedule(void)
309 {
310         /* This function must not have any "auto" variables, otherwise
311          * the compiler might put them on the stack of the process
312          * being switched out.
313          */
314         static struct Process *old_process;
315         static cpuflags_t flags;
316
317         /* Remember old process to save its context later */
318         old_process = CurrentProcess;
319
320 #ifdef IRQ_RUNNING
321         /* Scheduling in interrupts is a nono. */
322         ASSERT(!IRQ_RUNNING());
323 #endif
324
325         /* Poll on the ready queue for the first ready process */
326         IRQ_SAVE_DISABLE(flags);
327         while (!(CurrentProcess = (struct Process *)list_remHead(&ProcReadyList)))
328         {
329                 /*
330                  * Make sure we physically reenable interrupts here, no matter what
331                  * the current task status is. This is important because if we
332                  * are idle-spinning, we must allow interrupts, otherwise no
333                  * process will ever wake up.
334                  *
335                  * \todo If there was a way to write sig_wait() so that it does not
336                  * disable interrupts while waiting, there would not be any
337                  * reason to do this.
338                  */
339                 IRQ_ENABLE;
340                 CPU_IDLE;
341                 IRQ_DISABLE;
342         }
343         IRQ_RESTORE(flags);
344
345         /*
346          * Optimization: don't switch contexts when the active
347          * process has not changed.
348          */
349         if (CurrentProcess != old_process)
350         {
351                 static cpustack_t *dummy;
352
353 #if CONFIG_KERN_PREEMPTIVE
354                 /* Reset quantum for this process */
355                 Quantum = CONFIG_KERN_QUANTUM;
356 #endif
357
358                 /* Save context of old process and switch to new process. If there is no
359                  * old process, we save the old stack pointer into a dummy variable that
360                  * we ignore. In fact, this happens only when the old process has just
361                  * exited.
362                  * TODO: Instead of physically clearing the process at exit time, a zombie
363                  * list should be created.
364                  */
365                 asm_switch_context(&CurrentProcess->stack, old_process ? &old_process->stack : &dummy);
366         }
367
368         /* This RET resumes the execution on the new process */
369 }
370
371
372 /**
373  * Terminate the current process
374  */
375 void proc_exit(void)
376 {
377 #if CONFIG_KERN_MONITOR
378         monitor_remove(CurrentProcess);
379 #endif
380
381 #if CONFIG_KERN_HEAP
382         /*
383          * The following code is BROKEN.
384          * We are freeing our own stack before entering proc_schedule()
385          * BAJO: A correct fix would be to rearrange the scheduler with
386          *  an additional parameter which frees the old stack/process
387          *  after a context switch.
388          */
389         if (CurrentProcess->flags & PF_FREESTACK)
390                 heap_free(CurrentProcess->stack_base, CurrentProcess->stack_size);
391         heap_free(CurrentProcess);
392 #endif
393
394 #if (ARCH & ARCH_EMUL)
395 #warning This is wrong
396         /* Reinsert process stack in free list */
397         ADDHEAD(&StackFreeList, (Node *)(CurrentProcess->stack
398                 - (CONFIG_KERN_DEFSTACKSIZE / sizeof(cpustack_t))));
399
400         /*
401          * NOTE: At this point the first two words of what used
402          * to be our stack contain a list node. From now on, we
403          * rely on the compiler not reading/writing the stack.
404          */
405 #endif /* ARCH_EMUL */
406
407         CurrentProcess = NULL;
408         proc_schedule();
409         /* not reached */
410 }
411
412
413 /**
414  * Co-operative context switch
415  */
416 void proc_switch(void)
417 {
418         /* Just like proc_schedule, this function must not have auto variables. */
419         static cpuflags_t flags;
420
421         IRQ_SAVE_DISABLE(flags);
422         SCHED_ENQUEUE(CurrentProcess);
423         IRQ_RESTORE(flags);
424
425         proc_schedule();
426 }
427
428
429 /**
430  * Get the pointer to the current process
431  */
432 struct Process *proc_current(void)
433 {
434         return CurrentProcess;
435 }
436
437 /**
438  * Get the pointer to the user data of the current process
439  */
440 iptr_t proc_current_user_data(void)
441 {
442         return CurrentProcess->user_data;
443 }
444
445
446 #if CONFIG_KERN_PREEMPTIVE
447
448 /**
449  * Disable preemptive task switching.
450  *
451  * The scheduler maintains a per-process nesting counter.  Task switching is
452  * effectively re-enabled only when the number of calls to proc_permit()
453  * matches the number of calls to proc_forbid().
454  *
455  * Calling functions that could sleep while task switching is disabled
456  * is dangerous, although supported.  Preemptive task switching is
457  * resumed while the process is sleeping and disabled again as soon as
458  * it wakes up again.
459  *
460  * \sa proc_permit()
461  */
462 void proc_forbid(void)
463 {
464         /* No need to protect against interrupts here. */
465         ++CurrentProcess->forbid_cnt;
466 }
467
468 /**
469  * Re-enable preemptive task switching.
470  *
471  * \sa proc_forbid()
472  */
473 void proc_permit(void)
474 {
475         /* No need to protect against interrupts here. */
476         --CurrentProcess->forbid_cnt;
477 }
478
479 #endif /* CONFIG_KERN_PREEMPTIVE */
480
481
482 #if 0 /* Simple testcase for the scheduler */
483
484 #include <drv/timer.h>
485
486 /**
487  * Proc scheduling test subthread 1
488  */
489 static void NORETURN proc_test_thread1(void)
490 {
491         for (;;)
492         {
493                 kputs(">task 1\n");
494                 timer_delay(50);
495                 proc_switch();
496         }
497 }
498
499 /**
500  * Proc scheduling test subthread 2
501  */
502 static void NORETURN proc_test_thread2(void)
503 {
504         for (;;)
505         {
506                 kputs(">task 2\n");
507                 timer_delay(75);
508                 proc_switch();
509         }
510 }
511
512 static cpustack_t proc_test_stack1[CONFIG_KERN_DEFSTACKSIZE/sizeof(cpustack_t)];
513 static cpustack_t proc_test_stack2[CONFIG_KERN_DEFSTACKSIZE/sizeof(cpustack_t)];
514
515 /**
516  * Proc scheduling test
517  */
518 void NORETURN proc_test(void)
519 {
520         proc_new(proc_test_thread1, NULL, sizeof(proc_test_stack1), proc_test_stack1);
521         proc_new(proc_test_thread2, NULL, sizeof(proc_test_stack2), proc_test_stack2);
522         kputs("Created tasks\n");
523
524         kputs("stack1:\n");
525         kdump(proc_test_stack1+sizeof(proc_test_stack1)-64, 64);
526         kputs("stack2:\n");
527         kdump(proc_test_stack2+sizeof(proc_test_stack1)-64, 64);
528
529         for (;;)
530         {
531                 kputs(">main task\n");
532                 timer_delay(93);
533                 proc_switch();
534         }
535
536         ASSERT(false);
537 }
538 #endif