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