proc_test: enlarge processes' stack size to KERN_MINSTACKSIZE * 3.
[bertos.git] / bertos / kern / proc_test.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 2009 Develer S.r.l. (http://www.develer.com/)
30  * -->
31  *
32  *
33  * \brief Test kernel preemption.
34  *
35  * This testcase spawns TASKS parallel threads that runs for TIME seconds. They
36  * continuously spin updating a global counter (one counter for each thread).
37  *
38  * At exit each thread checks if the others have been che chance to update
39  * their own counter. If not, it means the preemption didn't occur and the
40  * testcase returns an error message.
41  *
42  * Otherwise, if all the threads have been able to update their own counter it
43  * means preemption successfully occurs, since there is no active sleep inside
44  * each thread's implementation.
45  *
46  * \author Andrea Righi <arighi@develer.com>
47  *
48  * $test$: cp bertos/cfg/cfg_proc.h $cfgdir/
49  * $test$: echo  "#undef CONFIG_KERN" >> $cfgdir/cfg_proc.h
50  * $test$: echo "#define CONFIG_KERN 1" >> $cfgdir/cfg_proc.h
51  * $test$: echo  "#undef CONFIG_KERN_PRI" >> $cfgdir/cfg_proc.h
52  * $test$: echo "#define CONFIG_KERN_PRI 1" >> $cfgdir/cfg_proc.h
53  * $test$: echo  "#undef CONFIG_KERN_PREEMPT" >> $cfgdir/cfg_proc.h
54  * $test$: echo "#define CONFIG_KERN_PREEMPT 1" >> $cfgdir/cfg_proc.h
55  * $test$: cp bertos/cfg/cfg_monitor.h $cfgdir/
56  * $test$: sed -i "s/CONFIG_KERN_MONITOR 0/CONFIG_KERN_MONITOR 1/" $cfgdir/cfg_monitor.h
57  * $test$: cp bertos/cfg/cfg_signal.h $cfgdir/
58  * $test$: echo  "#undef CONFIG_KERN_SIGNALS" >> $cfgdir/cfg_signal.h
59  * $test$: echo "#define CONFIG_KERN_SIGNALS 1" >> $cfgdir/cfg_signal.h
60  *
61  */
62
63 #include <stdio.h> // sprintf
64 #include <string.h> // memset
65
66 #include <kern/proc.h>
67 #include <kern/irq.h>
68 #include <kern/monitor.h>
69
70 #include <drv/timer.h>
71 #include <cfg/test.h>
72 #include <cfg/cfg_proc.h>
73
74 enum
75 {
76         TEST_OK = 1,
77         TEST_FAIL = 2,
78 };
79
80 /* Number of tasks to spawn */
81 #define TASKS   8
82
83 static char name[TASKS][32];
84
85 static unsigned int done[TASKS];
86
87 static cpu_atomic_t barrier[TASKS];
88 static cpu_atomic_t main_barrier;
89
90 /* Base time delay for processes using timer_delay() */
91 #define DELAY   5
92
93 // Define process stacks for test.
94 #define WORKER_STACK_SIZE KERN_MINSTACKSIZE * 3
95
96 #if CONFIG_KERN_HEAP
97 #define WORKER_STACK(id)         NULL
98 #else /* !CONFIG_KERN_HEAP */
99 static cpu_stack_t worker_stack[TASKS][(WORKER_STACK_SIZE +
100                         sizeof(cpu_stack_t) - 1) / sizeof(cpu_stack_t)];
101 #define WORKER_STACK(id)         (&worker_stack[id][0])
102 #endif /* CONFIG_KERN_HEAP */
103
104 static int prime_numbers[] =
105 {
106         1, 3, 5, 7, 11, 13, 17, 19,
107         23, 29, 31, 37, 41, 43, 47, 53,
108 };
109 STATIC_ASSERT(TASKS <= countof(prime_numbers));
110
111 #if CONFIG_KERN_PREEMPT
112 /* Time to run each preemptible thread (in seconds) */
113 #define TIME    10
114
115 static unsigned long preempt_counter[TASKS];
116 static unsigned int preempt_done[TASKS];
117 #endif
118
119 static void cleanup(void)
120 {
121 #if CONFIG_KERN_PREEMPT
122         // Clear shared data (this is needed when this testcase is embedded in
123         // the demo application).
124         memset(preempt_counter, 0, sizeof(preempt_counter));
125         memset(preempt_done, 0, sizeof(preempt_done));
126 #endif /* CONFIG_KERN_PREEMPT */
127         memset(done, 0, sizeof(done));
128         memset(barrier, 0, sizeof(barrier));
129         main_barrier = 0;
130 }
131
132 static void worker(void)
133 {
134         ssize_t pid = (ssize_t)proc_currentUserData();
135         long tot = prime_numbers[pid - 1];
136         unsigned int my_count = 0;
137         int i;
138
139         barrier[pid - 1] = 1;
140         /* Synchronize on the main barrier */
141         while (!main_barrier)
142                 proc_yield();
143         for (i = 0; i < tot; i++)
144         {
145                 my_count++;
146                 PROC_ATOMIC(kprintf("> %s[%zd] running\n", __func__, pid));
147                 timer_delay(tot * DELAY);
148         }
149         done[pid - 1] = 1;
150         PROC_ATOMIC(kprintf("> %s[%zd] completed\n", __func__, pid));
151 }
152
153 static int worker_test(void)
154 {
155         ssize_t i;
156
157         // Init the test processes
158         cleanup();
159         kputs("Run Proc test..\n");
160         for (i = 0; i < TASKS; i++)
161         {
162                 name[i][0] = '\0';
163                 snprintf(&name[i][0], sizeof(name[i]), "worker_%zd", i + 1);
164                 name[i][sizeof(name[i]) - 1] = '\0';
165                 proc_new_with_name(name[i], worker, (iptr_t)(i + 1),
166                                 WORKER_STACK_SIZE, WORKER_STACK(i));
167         }
168         /* Synchronize on start */
169         while (1)
170         {
171                 for (i = 0; i < TASKS; i++)
172                         if (!barrier[i])
173                                 break;
174                 if (i == TASKS)
175                         break;
176                 proc_yield();
177         }
178         main_barrier = 1;
179         MEMORY_BARRIER;
180         kputs("> Main: Processes started\n");
181         while (1)
182         {
183                 for (i = 0; i < TASKS; i++)
184                 {
185                         if (!done[i])
186                                 break;
187                 }
188                 if (i == TASKS)
189                         break;
190                 monitor_report();
191                 timer_delay(93);
192         }
193         kputs("> Main: process test finished..ok!\n");
194         return 0;
195 }
196
197 #if CONFIG_KERN_PREEMPT
198 static void preempt_worker(void)
199 {
200         ssize_t pid = (ssize_t)proc_currentUserData();
201         unsigned long *my_count = &preempt_counter[pid - 1];
202         ticks_t start, stop;
203         int i;
204
205         barrier[pid - 1] = 1;
206         /* Synchronize on the main barrier */
207         while (!main_barrier)
208                 proc_yield();
209         PROC_ATOMIC(kprintf("> %s[%zd] running\n", __func__, pid));
210         start = timer_clock();
211         stop  = ms_to_ticks(TIME * 1000);
212         while (timer_clock() - start < stop)
213         {
214                 IRQ_ASSERT_ENABLED();
215                 (*my_count)++;
216                 /* be sure to wrap to a value different than 0 */
217                 if (UNLIKELY(*my_count == (unsigned int)~0))
218                         *my_count = 1;
219         }
220         PROC_ATOMIC(kprintf("> %s[%zd] completed: (counter = %lu)\n",
221                                 __func__, pid, *my_count));
222         for (i = 0; i < TASKS; i++)
223                 if (!preempt_counter[i])
224                 {
225                         preempt_done[pid - 1] = TEST_FAIL;
226                         return;
227                 }
228         preempt_done[pid - 1] = TEST_OK;
229 }
230
231 static int preempt_worker_test(void)
232 {
233         unsigned long score = 0;
234         ssize_t i;
235
236         // Init the test processes
237         cleanup();
238         kputs("Run Preemption test..\n");
239         for (i = 0; i < TASKS; i++)
240         {
241                 name[i][0] = '\0';
242                 snprintf(&name[i][0], sizeof(name[i]),
243                                 "preempt_worker_%zd", i + 1);
244                 name[i][sizeof(name[i]) - 1] = '\0';
245                 proc_new_with_name(name[i], preempt_worker, (iptr_t)(i + 1),
246                                 WORKER_STACK_SIZE, WORKER_STACK(i));
247         }
248         kputs("> Main: Processes created\n");
249         /* Synchronize on start */
250         while (1)
251         {
252                 for (i = 0; i < TASKS; i++)
253                         if (!barrier[i])
254                                 break;
255                 if (i == TASKS)
256                         break;
257                 proc_yield();
258         }
259         /* Now all threads have been created, start them all */
260         main_barrier = 1;
261         MEMORY_BARRIER;
262         kputs("> Main: Processes started\n");
263         while (1)
264         {
265                 for (i = 0; i < TASKS; i++)
266                 {
267                         if (!preempt_done[i])
268                                 break;
269                         else if (preempt_done[i] == TEST_FAIL)
270                         {
271                                 kputs("> Main: process test finished..fail!\n");
272                                 return -1;
273                         }
274                 }
275                 if (i == TASKS)
276                         break;
277                 monitor_report();
278                 timer_delay(1000);
279         }
280         for (i = 0; i < TASKS; i++)
281                 score += preempt_counter[i];
282         kputs("> Main: process test finished..ok!\n");
283         kprintf("> Score: %lu\n", score);
284         return 0;
285 }
286 #endif /* CONFIG_KERN_PREEMPT */
287
288 #if CONFIG_KERN_SIGNALS & CONFIG_KERN_PRI
289
290 // Define params to test priority
291 #define PROC_PRI_TEST(num) static void proc_pri_test##num(void) \
292 { \
293         struct Process *main_proc = (struct Process *) proc_currentUserData(); \
294         kputs("> Process: " #num "\n"); \
295         sig_signal(main_proc, SIG_USER##num); \
296 }
297
298 // Default priority is 0
299 #define PROC_PRI_TEST_INIT(num, proc)                                   \
300 do {                                                                    \
301         struct Process *p = proc_new(proc_pri_test##num, (proc),        \
302                                         WORKER_STACK_SIZE,              \
303                                         WORKER_STACK(num));             \
304         proc_setPri(p, num + 1);                                        \
305 } while (0)
306
307 PROC_PRI_TEST(0)
308 PROC_PRI_TEST(1)
309 PROC_PRI_TEST(2)
310
311 static int prio_worker_test(void)
312 {
313         struct Process *curr = proc_current();
314         int orig_pri = curr->link.pri;
315         int ret = 0;
316
317         // test process priority
318         // main process must have the higher priority to check signals received
319         proc_setPri(proc_current(), 10);
320
321         kputs("Run Priority test..\n");
322         // the order in which the processes are created is important!
323         PROC_PRI_TEST_INIT(0, curr);
324         PROC_PRI_TEST_INIT(1, curr);
325         PROC_PRI_TEST_INIT(2, curr);
326
327         // signals must be: USER2, 1, 0 in order
328         sigmask_t signals = sig_wait(SIG_USER0 | SIG_USER1 | SIG_USER2);
329         if (!(signals & SIG_USER2))
330         {
331                 ret = -1;
332                 goto out;
333         }
334         signals = sig_wait(SIG_USER0 | SIG_USER1 | SIG_USER2);
335         if (!(signals & SIG_USER1))
336         {
337                 ret = -1;
338                 goto out;
339         }
340         signals = sig_wait(SIG_USER0 | SIG_USER1 | SIG_USER2);
341         if (!(signals & SIG_USER0))
342         {
343                 ret = -1;
344                 goto out;
345         }
346         // All processes must have quit by now, but just in case...
347         signals = sig_waitTimeout(SIG_USER0 | SIG_USER1 | SIG_USER2, 200);
348         if (signals & (SIG_USER0 | SIG_USER1 | SIG_USER2))
349         {
350                 ret = -1;
351                 goto out;
352         }
353         if (signals & SIG_TIMEOUT)
354         {
355                 kputs("Priority test successfull.\n");
356         }
357 out:
358         proc_setPri(proc_current(), orig_pri);
359         if (ret != 0)
360                 kputs("Priority test failed.\n");
361         return ret;
362 }
363 #endif /* CONFIG_KERN_SIGNALS & CONFIG_KERN_PRI */
364
365 /**
366  * Process scheduling test
367  */
368 int proc_testRun(void)
369 {
370         /* Start tests */
371         worker_test();
372 #if CONFIG_KERN_PREEMPT
373         preempt_worker_test();
374 #endif /* CONFIG_KERN_PREEMPT */
375 #if CONFIG_KERN_SIGNALS & CONFIG_KERN_PRI
376         prio_worker_test();
377 #endif /* CONFIG_KERN_SIGNALS & CONFIG_KERN_PRI */
378         return 0;
379 }
380
381 int proc_testSetup(void)
382 {
383         kdbg_init();
384
385         kprintf("Init Timer..");
386         timer_init();
387         kprintf("Done.\n");
388
389         kprintf("Init Process..");
390         proc_init();
391         kprintf("Done.\n");
392
393         return 0;
394 }
395
396 int proc_testTearDown(void)
397 {
398         kputs("TearDown Process test.\n");
399         return 0;
400 }
401
402 TEST_MAIN(proc);