source: mainline/kernel/test/synch/workq-test-core.h@ 44a7ee5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 44a7ee5 was 44a7ee5, checked in by Jiri Svoboda <jiri@…>, 8 years ago

memxxx functions should be provided in the kernel via the same header as in userspace (mem.h).

  • Property mode set to 100644
File size: 5.3 KB
Line 
1/*
2 * Copyright (c) 2012 Adam Hraska
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <test.h>
30#include <arch.h>
31#include <atomic.h>
32#include <print.h>
33#include <proc/thread.h>
34#include <mem.h>
35#include <synch/workqueue.h>
36
37
38typedef struct test_work {
39 work_t work_item;
40 int master;
41 int wave;
42 int count_down;
43} test_work_t;
44
45static atomic_t call_cnt[WAVES];
46
47
48/* Fwd decl - implement in your actual test file.. */
49static int core_workq_enqueue(work_t *work_item, work_func_t func);
50
51
52static bool new_wave(test_work_t *work)
53{
54 ++work->wave;
55
56 if (work->wave < WAVES) {
57 work->count_down = COUNT;
58 return true;
59 } else {
60 return false;
61 }
62}
63
64
65static int is_pow2(int num)
66{
67 unsigned n = (unsigned)num;
68 return (n != 0) && 0 == (n & (n-1));
69}
70
71static test_work_t * create_child(test_work_t *work)
72{
73 test_work_t *child = malloc(sizeof(test_work_t), 0);
74 ASSERT(child);
75 if (child) {
76 child->master = false;
77 child->wave = work->wave;
78 child->count_down = work->count_down;
79 }
80
81 return child;
82}
83
84static void free_work(test_work_t *work)
85{
86 memsetb(work, sizeof(test_work_t), 0xfa);
87 free(work);
88}
89
90static void reproduce(work_t *work_item)
91{
92 /* Ensure work_item is ours for the taking. */
93 memsetb(work_item, sizeof(work_t), 0xec);
94
95 test_work_t *work = (test_work_t *)work_item;
96
97 atomic_inc(&call_cnt[work->wave]);
98
99 if (0 < work->count_down) {
100 /* Sleep right before creating the last generation. */
101 if (1 == work->count_down) {
102 bool sleeping_wave = ((work->wave % 2) == 1);
103
104 /* Master never sleeps. */
105 if (sleeping_wave && !work->master) {
106 thread_usleep(WAVE_SLEEP_MS * 1000);
107 }
108 }
109
110 --work->count_down;
111
112 /*
113 * Enqueue a child if count_down is power-of-2.
114 * Leads to exponential growth.
115 */
116 if (is_pow2(work->count_down + 1)) {
117 test_work_t *child = create_child(work);
118 if (child) {
119 if (!core_workq_enqueue(&child->work_item, reproduce))
120 free_work(child);
121 }
122 }
123
124 if (!core_workq_enqueue(work_item, reproduce)) {
125 if (work->master)
126 TPRINTF("\nErr: Master work item exiting prematurely!\n");
127
128 free_work(work);
129 }
130 } else {
131 /* We're done with this wave - only the master survives. */
132
133 if (work->master && new_wave(work)) {
134 if (!core_workq_enqueue(work_item, reproduce)) {
135 TPRINTF("\nErr: Master work could not start a new wave!\n");
136 free_work(work);
137 }
138 } else {
139 if (work->master)
140 TPRINTF("\nMaster work item done.\n");
141
142 free_work(work);
143 }
144 }
145}
146
147static const char *run_workq_core(bool end_prematurely)
148{
149 for (int i = 0; i < WAVES; ++i) {
150 atomic_set(&call_cnt[i], 0);
151 }
152
153 test_work_t *work = malloc(sizeof(test_work_t), 0);
154
155 work->master = true;
156 work->wave = 0;
157 work->count_down = COUNT;
158
159 /*
160 * k == COUNT_POW
161 * 2^k == COUNT + 1
162 *
163 * We have "k" branching points. Therefore:
164 * exp_call_cnt == k*2^(k-1) + 2^k == (k + 2) * 2^(k-1)
165 */
166 size_t exp_call_cnt = (COUNT_POW + 2) * (1 << (COUNT_POW - 1));
167
168 TPRINTF("waves: %d, count_down: %d, total expected calls: %zu\n",
169 WAVES, COUNT, exp_call_cnt * WAVES);
170
171
172 core_workq_enqueue(&work->work_item, reproduce);
173
174 size_t sleep_cnt = 0;
175 /* At least 40 seconds total (or 2 sec to end while there's work). */
176 size_t max_sleep_secs = end_prematurely ? 2 : MAIN_MAX_SLEEP_SEC;
177 size_t max_sleep_cnt = (max_sleep_secs * 1000) / MAIN_POLL_SLEEP_MS;
178
179 for (int i = 0; i < WAVES; ++i) {
180 while (atomic_get(&call_cnt[i]) < exp_call_cnt
181 && sleep_cnt < max_sleep_cnt) {
182 TPRINTF(".");
183 thread_usleep(MAIN_POLL_SLEEP_MS * 1000);
184 ++sleep_cnt;
185 }
186 }
187
188 bool success = true;
189
190 for (int i = 0; i < WAVES; ++i) {
191 if (atomic_get(&call_cnt[i]) == exp_call_cnt) {
192 TPRINTF("Ok: %" PRIua " calls in wave %d, as expected.\n",
193 atomic_get(&call_cnt[i]), i);
194 } else {
195 success = false;
196 TPRINTF("Error: %" PRIua " calls in wave %d, but %zu expected.\n",
197 atomic_get(&call_cnt[i]), i, exp_call_cnt);
198 }
199 }
200
201
202 if (success)
203 return NULL;
204 else {
205 return "Failed to invoke the expected number of calls.\n";
206 }
207}
Note: See TracBrowser for help on using the repository browser.