4 * This file is part of BeRTOS.
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.
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.
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
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.
29 * Copyright 2009 Develer S.r.l. (http://www.develer.com/)
33 * \brief Test kernel preemption.
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).
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.
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.
46 * \author Andrea Righi <arighi@develer.com>
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
67 #include <stdio.h> // sprintf
68 #include <string.h> // memset
70 #include <kern/proc.h>
72 #include <kern/monitor.h>
74 #include <drv/timer.h>
76 #include <cfg/cfg_proc.h>
84 /* Number of tasks to spawn */
87 static char name[TASKS][32];
89 static unsigned int done[TASKS];
91 static cpu_atomic_t barrier[TASKS];
92 static cpu_atomic_t main_barrier;
94 /* Base time delay for processes using timer_delay() */
97 // Define process stacks for test.
98 #define WORKER_STACK_SIZE KERN_MINSTACKSIZE * 3
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 */
108 static int prime_numbers[] =
110 1, 3, 5, 7, 11, 13, 17, 19,
111 23, 29, 31, 37, 41, 43, 47, 53,
113 STATIC_ASSERT(TASKS <= countof(prime_numbers));
115 #if CONFIG_KERN_PREEMPT
116 /* Time to run each preemptible thread (in seconds) */
119 static unsigned long preempt_counter[TASKS];
120 static unsigned int preempt_done[TASKS];
123 static void cleanup(void)
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));
136 static void worker(void)
138 ssize_t pid = (ssize_t)proc_currentUserData();
139 long tot = prime_numbers[pid - 1];
140 unsigned int my_count = 0;
143 barrier[pid - 1] = 1;
144 /* Synchronize on the main barrier */
145 while (!main_barrier)
147 for (i = 0; i < tot; i++)
150 PROC_ATOMIC(kprintf("> %s[%zd] running\n", __func__, pid));
151 timer_delay(tot * DELAY);
154 PROC_ATOMIC(kprintf("> %s[%zd] completed\n", __func__, pid));
157 static int worker_test(void)
161 // Init the test processes
163 kputs("Run Proc test..\n");
164 for (i = 0; i < TASKS; i++)
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));
172 /* Synchronize on start */
175 for (i = 0; i < TASKS; i++)
184 kputs("> Main: Processes started\n");
187 for (i = 0; i < TASKS; i++)
197 kputs("> Main: process test finished..ok!\n");
201 #if CONFIG_KERN_PREEMPT
202 static void preempt_worker(void)
204 ssize_t pid = (ssize_t)proc_currentUserData();
205 unsigned long *my_count = &preempt_counter[pid - 1];
209 barrier[pid - 1] = 1;
210 /* Synchronize on the main barrier */
211 while (!main_barrier)
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)
218 IRQ_ASSERT_ENABLED();
220 /* be sure to wrap to a value different than 0 */
221 if (UNLIKELY(*my_count == (unsigned int)~0))
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])
229 preempt_done[pid - 1] = TEST_FAIL;
232 preempt_done[pid - 1] = TEST_OK;
235 static int preempt_worker_test(void)
237 unsigned long score = 0;
240 // Init the test processes
242 kputs("Run Preemption test..\n");
243 for (i = 0; i < TASKS; i++)
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));
252 kputs("> Main: Processes created\n");
253 /* Synchronize on start */
256 for (i = 0; i < TASKS; i++)
263 /* Now all threads have been created, start them all */
266 kputs("> Main: Processes started\n");
269 for (i = 0; i < TASKS; i++)
271 if (!preempt_done[i])
273 else if (preempt_done[i] == TEST_FAIL)
275 kputs("> Main: process test finished..fail!\n");
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);
290 #endif /* CONFIG_KERN_PREEMPT */
292 #if CONFIG_KERN_SIGNALS & CONFIG_KERN_PRI
294 // Define params to test priority
295 #define PROC_PRI_TEST(num) static void proc_pri_test##num(void) \
297 struct Process *main_proc = (struct Process *) proc_currentUserData(); \
298 kputs("> Process: " #num "\n"); \
299 sig_signal(main_proc, SIG_USER##num); \
302 // Default priority is 0
303 #define PROC_PRI_TEST_INIT(num, proc) \
305 struct Process *p = proc_new(proc_pri_test##num, (proc), \
307 WORKER_STACK(num)); \
308 proc_setPri(p, num + 1); \
315 static int prio_worker_test(void)
317 struct Process *curr = proc_current();
318 int orig_pri = curr->link.pri;
321 // test process priority
322 // main process must have the higher priority to check signals received
323 proc_setPri(proc_current(), 10);
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);
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))
338 signals = sig_wait(SIG_USER0 | SIG_USER1 | SIG_USER2);
339 if (!(signals & SIG_USER1))
344 signals = sig_wait(SIG_USER0 | SIG_USER1 | SIG_USER2);
345 if (!(signals & SIG_USER0))
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))
357 if (signals & SIG_TIMEOUT)
359 kputs("Priority test successfull.\n");
362 proc_setPri(proc_current(), orig_pri);
364 kputs("Priority test failed.\n");
367 #endif /* CONFIG_KERN_SIGNALS & CONFIG_KERN_PRI */
370 * Process scheduling test
372 int proc_testRun(void)
376 #if CONFIG_KERN_PREEMPT
377 preempt_worker_test();
378 #endif /* CONFIG_KERN_PREEMPT */
379 #if CONFIG_KERN_SIGNALS & CONFIG_KERN_PRI
381 #endif /* CONFIG_KERN_SIGNALS & CONFIG_KERN_PRI */
385 int proc_testSetup(void)
389 kprintf("Init Timer..");
393 kprintf("Init Process..");
400 int proc_testTearDown(void)
402 kputs("TearDown Process test.\n");