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