source: mainline/kernel/test/synch/workq-test-core.h@ 63e27ef

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

ASSERT → assert

  • 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 <assert.h>
30#include <test.h>
31#include <arch.h>
32#include <atomic.h>
33#include <print.h>
34#include <proc/thread.h>
35#include <mem.h>
36#include <synch/workqueue.h>
37
38
39typedef struct test_work {
40 work_t work_item;
41 int master;
42 int wave;
43 int count_down;
44} test_work_t;
45
46static atomic_t call_cnt[WAVES];
47
48
49/* Fwd decl - implement in your actual test file.. */
50static int core_workq_enqueue(work_t *work_item, work_func_t func);
51
52
53static bool new_wave(test_work_t *work)
54{
55 ++work->wave;
56
57 if (work->wave < WAVES) {
58 work->count_down = COUNT;
59 return true;
60 } else {
61 return false;
62 }
63}
64
65
66static int is_pow2(int num)
67{
68 unsigned n = (unsigned)num;
69 return (n != 0) && 0 == (n & (n-1));
70}
71
72static test_work_t * create_child(test_work_t *work)
73{
74 test_work_t *child = malloc(sizeof(test_work_t), 0);
75 assert(child);
76 if (child) {
77 child->master = false;
78 child->wave = work->wave;
79 child->count_down = work->count_down;
80 }
81
82 return child;
83}
84
85static void free_work(test_work_t *work)
86{
87 memsetb(work, sizeof(test_work_t), 0xfa);
88 free(work);
89}
90
91static void reproduce(work_t *work_item)
92{
93 /* Ensure work_item is ours for the taking. */
94 memsetb(work_item, sizeof(work_t), 0xec);
95
96 test_work_t *work = (test_work_t *)work_item;
97
98 atomic_inc(&call_cnt[work->wave]);
99
100 if (0 < work->count_down) {
101 /* Sleep right before creating the last generation. */
102 if (1 == work->count_down) {
103 bool sleeping_wave = ((work->wave % 2) == 1);
104
105 /* Master never sleeps. */
106 if (sleeping_wave && !work->master) {
107 thread_usleep(WAVE_SLEEP_MS * 1000);
108 }
109 }
110
111 --work->count_down;
112
113 /*
114 * Enqueue a child if count_down is power-of-2.
115 * Leads to exponential growth.
116 */
117 if (is_pow2(work->count_down + 1)) {
118 test_work_t *child = create_child(work);
119 if (child) {
120 if (!core_workq_enqueue(&child->work_item, reproduce))
121 free_work(child);
122 }
123 }
124
125 if (!core_workq_enqueue(work_item, reproduce)) {
126 if (work->master)
127 TPRINTF("\nErr: Master work item exiting prematurely!\n");
128
129 free_work(work);
130 }
131 } else {
132 /* We're done with this wave - only the master survives. */
133
134 if (work->master && new_wave(work)) {
135 if (!core_workq_enqueue(work_item, reproduce)) {
136 TPRINTF("\nErr: Master work could not start a new wave!\n");
137 free_work(work);
138 }
139 } else {
140 if (work->master)
141 TPRINTF("\nMaster work item done.\n");
142
143 free_work(work);
144 }
145 }
146}
147
148static const char *run_workq_core(bool end_prematurely)
149{
150 for (int i = 0; i < WAVES; ++i) {
151 atomic_set(&call_cnt[i], 0);
152 }
153
154 test_work_t *work = malloc(sizeof(test_work_t), 0);
155
156 work->master = true;
157 work->wave = 0;
158 work->count_down = COUNT;
159
160 /*
161 * k == COUNT_POW
162 * 2^k == COUNT + 1
163 *
164 * We have "k" branching points. Therefore:
165 * exp_call_cnt == k*2^(k-1) + 2^k == (k + 2) * 2^(k-1)
166 */
167 size_t exp_call_cnt = (COUNT_POW + 2) * (1 << (COUNT_POW - 1));
168
169 TPRINTF("waves: %d, count_down: %d, total expected calls: %zu\n",
170 WAVES, COUNT, exp_call_cnt * WAVES);
171
172
173 core_workq_enqueue(&work->work_item, reproduce);
174
175 size_t sleep_cnt = 0;
176 /* At least 40 seconds total (or 2 sec to end while there's work). */
177 size_t max_sleep_secs = end_prematurely ? 2 : MAIN_MAX_SLEEP_SEC;
178 size_t max_sleep_cnt = (max_sleep_secs * 1000) / MAIN_POLL_SLEEP_MS;
179
180 for (int i = 0; i < WAVES; ++i) {
181 while (atomic_get(&call_cnt[i]) < exp_call_cnt
182 && sleep_cnt < max_sleep_cnt) {
183 TPRINTF(".");
184 thread_usleep(MAIN_POLL_SLEEP_MS * 1000);
185 ++sleep_cnt;
186 }
187 }
188
189 bool success = true;
190
191 for (int i = 0; i < WAVES; ++i) {
192 if (atomic_get(&call_cnt[i]) == exp_call_cnt) {
193 TPRINTF("Ok: %" PRIua " calls in wave %d, as expected.\n",
194 atomic_get(&call_cnt[i]), i);
195 } else {
196 success = false;
197 TPRINTF("Error: %" PRIua " calls in wave %d, but %zu expected.\n",
198 atomic_get(&call_cnt[i]), i, exp_call_cnt);
199 }
200 }
201
202
203 if (success)
204 return NULL;
205 else {
206 return "Failed to invoke the expected number of calls.\n";
207 }
208}
Note: See TracBrowser for help on using the repository browser.