1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /* This test covers deprecated API.  Avoid inappropriate diagnostics
8  * about the use of that API.
9  */
10 #include <zephyr/toolchain.h>
11 #undef __deprecated
12 #define __deprecated
13 #undef __DEPRECATED_MACRO
14 #define __DEPRECATED_MACRO
15 
16 #include <zephyr/ztest.h>
17 
18 #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
19 #define COOPHI_PRIORITY K_PRIO_COOP(0) /* = -4 */
20 /* SYSTEM_WORKQUEUE_PRIORITY = -3 */
21 /* ZTEST_THREAD_PRIORITY = -2 */
22 #define COOPLO_PRIORITY K_PRIO_COOP(3) /* = -1 */
23 #define PREEMPT_PRIORITY K_PRIO_PREEMPT(1) /* = 1 */
24 
25 #define DELAY_MS 100
26 #define DELAY_TIMEOUT K_MSEC(DELAY_MS)
27 
28 BUILD_ASSERT(COOPHI_PRIORITY < CONFIG_SYSTEM_WORKQUEUE_PRIORITY,
29 	     "COOPHI not higher priority than system workqueue");
30 BUILD_ASSERT(CONFIG_SYSTEM_WORKQUEUE_PRIORITY < CONFIG_ZTEST_THREAD_PRIORITY,
31 	     "System workqueue not higher priority than ZTEST");
32 BUILD_ASSERT(CONFIG_ZTEST_THREAD_PRIORITY < COOPLO_PRIORITY,
33 	     "ZTEST not higher priority than COOPLO");
34 BUILD_ASSERT(COOPLO_PRIORITY < 0,
35 	     "COOPLO not cooperative");
36 
37 /* Given by work thread to signal completion. */
38 static struct k_sem sync_sem;
39 
40 static bool run_flag = true;
41 
42 /* Given by test thread to release a work item. */
43 static struct k_sem rel_sem;
44 
45 /* Common work structures, to avoid dead references to stack objects
46  * if a test fails.
47  */
48 static struct k_work common_work;
49 static struct k_work common_work1;
50 static struct k_work_delayable dwork;
51 
52 /* Work synchronization objects must be in cache-coherent memory,
53  * which excludes stacks on some architectures.
54  */
55 static struct k_work_sync work_sync;
56 
57 static struct k_thread *main_thread;
58 
59 /* We have these threads, in strictly decreasing order of priority:
60  * * coophi: a high priority cooperative work queue
61  * * system: the standard system work queue
62  * * ztest thread: priority for threads running tests
63  * * cooplo : a low-priority cooperative work queue
64  * * preempt: a preemptible work queue
65  *
66  * The test infrastructure records the number of times each work queue
67  * executes in a counter.
68  *
69  * The common work handler also supports internal re-submission if
70  * configured to do so.
71  *
72  * There are three core handlers:
73  * * The basic one (counter_handler) increments the count of handler
74  *   invocations by work queue thread, optionally resubmits, then
75  *   releases the semaphore the test is waiting for.
76  * * The blocking one (rel_handler) waits until something invokes
77  *   handler_release() to allow it to complete by invoking
78  *   counter_handler().  This makes a work queue busy for arbitrary
79  *   periods, but requires something external to trigger the release.
80  * * The delaying one (delay_handler) waits for K_MSEC(DELAY_MS) before
81  *   invoking counter_handler().
82  */
83 static atomic_t resubmits_left;
84 
85 /* k_uptime_get32() on the last invocation of the core handler. */
86 static uint32_t volatile last_handle_ms;
87 
88 static K_THREAD_STACK_DEFINE(coophi_stack, STACK_SIZE);
89 static struct k_work_q coophi_queue;
90 static struct k_work_q not_start_queue;
91 static atomic_t coophi_ctr;
coophi_counter(void)92 static inline int coophi_counter(void)
93 {
94 	return atomic_get(&coophi_ctr);
95 }
96 
97 static K_THREAD_STACK_DEFINE(cooplo_stack, STACK_SIZE);
98 static struct k_work_q cooplo_queue;
99 static atomic_t cooplo_ctr;
cooplo_counter(void)100 static inline int cooplo_counter(void)
101 {
102 	return atomic_get(&cooplo_ctr);
103 }
104 
coop_counter(struct k_work_q * wq)105 static inline int coop_counter(struct k_work_q *wq)
106 {
107 	return (wq == &coophi_queue) ? coophi_counter()
108 		: (wq == &cooplo_queue) ? cooplo_counter()
109 		: -1;
110 }
111 
112 static K_THREAD_STACK_DEFINE(preempt_stack, STACK_SIZE);
113 static struct k_work_q preempt_queue;
114 static atomic_t preempt_ctr;
preempt_counter(void)115 static inline int preempt_counter(void)
116 {
117 	return atomic_get(&preempt_ctr);
118 }
119 
120 static K_THREAD_STACK_DEFINE(invalid_test_stack, STACK_SIZE);
121 static struct k_work_q invalid_test_queue;
122 
123 static atomic_t system_ctr;
system_counter(void)124 static inline int system_counter(void)
125 {
126 	return atomic_get(&system_ctr);
127 }
128 
reset_counters(void)129 static inline void reset_counters(void)
130 {
131 	/* If this fails the previous test didn't clean up */
132 	zassert_equal(k_sem_take(&sync_sem, K_NO_WAIT), -EBUSY);
133 	last_handle_ms = UINT32_MAX;
134 	atomic_set(&resubmits_left, 0);
135 	atomic_set(&coophi_ctr, 0);
136 	atomic_set(&system_ctr, 0);
137 	atomic_set(&cooplo_ctr, 0);
138 	atomic_set(&preempt_ctr, 0);
139 }
140 
counter_handler(struct k_work * work)141 static void counter_handler(struct k_work *work)
142 {
143 	last_handle_ms = k_uptime_get_32();
144 	if (k_current_get() == &coophi_queue.thread) {
145 		atomic_inc(&coophi_ctr);
146 	} else if (k_current_get() == &k_sys_work_q.thread) {
147 		atomic_inc(&system_ctr);
148 	} else if (k_current_get() == &cooplo_queue.thread) {
149 		atomic_inc(&cooplo_ctr);
150 	} else if (k_current_get() == &preempt_queue.thread) {
151 		atomic_inc(&preempt_ctr);
152 	}
153 	if (atomic_dec(&resubmits_left) > 0) {
154 		(void)k_work_submit_to_queue(NULL, work);
155 	} else {
156 		k_sem_give(&sync_sem);
157 	}
158 }
159 
handler_release(void)160 static inline void handler_release(void)
161 {
162 	k_sem_give(&rel_sem);
163 }
164 
async_release_cb(struct k_timer * timer)165 static void async_release_cb(struct k_timer *timer)
166 {
167 	handler_release();
168 }
169 
170 static K_TIMER_DEFINE(async_releaser, async_release_cb, NULL);
171 
async_release(void)172 static inline void async_release(void)
173 {
174 	k_timer_start(&async_releaser, K_TICKS(1), K_NO_WAIT);
175 }
176 
rel_handler(struct k_work * work)177 static void rel_handler(struct k_work *work)
178 {
179 	(void)k_sem_take(&rel_sem, K_FOREVER);
180 	counter_handler(work);
181 }
182 
delay_handler(struct k_work * work)183 static void delay_handler(struct k_work *work)
184 {
185 	k_sleep(K_MSEC(DELAY_MS));
186 	counter_handler(work);
187 }
188 
189 /* Check that standard initializations result in expected content. */
test_work_init(void)190 static void test_work_init(void)
191 {
192 	static K_WORK_DEFINE(fnstat, counter_handler);
193 
194 	static struct k_work stack;
195 
196 	k_work_init(&stack, counter_handler);
197 	zassert_mem_equal(&stack, &fnstat, sizeof(stack),
198 			  NULL);
199 }
200 
test_delayable_init(void)201 static void test_delayable_init(void)
202 {
203 	static K_WORK_DELAYABLE_DEFINE(fnstat, counter_handler);
204 
205 	static struct k_work_delayable stack;
206 
207 	k_work_init_delayable(&stack, counter_handler);
208 	zassert_mem_equal(&stack, &fnstat, sizeof(stack),
209 			  NULL);
210 }
211 
212 /* Check that submission to an unstarted queue is diagnosed. */
ZTEST(work,test_unstarted)213 ZTEST(work, test_unstarted)
214 {
215 	int rc;
216 
217 	k_work_init(&common_work, counter_handler);
218 	zassert_equal(k_work_busy_get(&common_work), 0);
219 
220 	rc = k_work_submit_to_queue(&not_start_queue, &common_work);
221 	zassert_equal(rc, -ENODEV);
222 }
223 
test_queue_start(void)224 static void test_queue_start(void)
225 {
226 	struct k_work_queue_config cfg = {
227 		.name = "wq.preempt",
228 	};
229 	k_work_queue_init(&preempt_queue);
230 	zassert_equal(preempt_queue.flags, 0);
231 	k_work_queue_start(&preempt_queue, preempt_stack, STACK_SIZE,
232 			    PREEMPT_PRIORITY, &cfg);
233 	zassert_equal(preempt_queue.flags, K_WORK_QUEUE_STARTED);
234 
235 	if (IS_ENABLED(CONFIG_THREAD_NAME)) {
236 		const char *tn = k_thread_name_get(&preempt_queue.thread);
237 
238 		zassert_true(tn != cfg.name);
239 		zassert_true(tn != NULL);
240 		zassert_str_equal(tn, cfg.name);
241 	}
242 
243 	cfg.name = NULL;
244 	zassert_equal(invalid_test_queue.flags, 0);
245 	k_work_queue_start(&invalid_test_queue, invalid_test_stack, STACK_SIZE,
246 			    PREEMPT_PRIORITY, &cfg);
247 	zassert_equal(invalid_test_queue.flags, K_WORK_QUEUE_STARTED);
248 
249 	if (IS_ENABLED(CONFIG_THREAD_NAME)) {
250 		const char *tn = k_thread_name_get(&invalid_test_queue.thread);
251 
252 		zassert_true(tn != cfg.name);
253 		zassert_true(tn != NULL);
254 		zassert_str_equal(tn, "");
255 	}
256 
257 	cfg.name = "wq.coophi";
258 	cfg.no_yield = true;
259 	k_work_queue_start(&coophi_queue, coophi_stack, STACK_SIZE,
260 			    COOPHI_PRIORITY, &cfg);
261 	zassert_equal(coophi_queue.flags,
262 		      K_WORK_QUEUE_STARTED | K_WORK_QUEUE_NO_YIELD, NULL);
263 
264 	cfg.name = "wq.cooplo";
265 	cfg.no_yield = true;
266 	k_work_queue_start(&cooplo_queue, cooplo_stack, STACK_SIZE,
267 			    COOPLO_PRIORITY, &cfg);
268 	zassert_equal(cooplo_queue.flags,
269 		      K_WORK_QUEUE_STARTED | K_WORK_QUEUE_NO_YIELD, NULL);
270 }
271 
272 /* Check validation of submission without a destination queue. */
ZTEST(work,test_null_queue)273 ZTEST(work, test_null_queue)
274 {
275 	int rc;
276 
277 	k_work_init(&common_work, counter_handler);
278 	zassert_equal(k_work_busy_get(&common_work), 0);
279 
280 	rc = k_work_submit_to_queue(NULL, &common_work);
281 	zassert_equal(rc, -EINVAL);
282 }
283 
284 /* Basic single-CPU check submitting with a non-blocking handler. */
ZTEST(work_1cpu,test_1cpu_simple_queue)285 ZTEST(work_1cpu, test_1cpu_simple_queue)
286 {
287 	int rc;
288 
289 	/* Reset state and use the non-blocking handler */
290 	reset_counters();
291 	k_work_init(&common_work, counter_handler);
292 	zassert_equal(k_work_busy_get(&common_work), 0);
293 	zassert_equal(k_work_is_pending(&common_work), false);
294 
295 	/* Submit to the cooperative queue */
296 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
297 	zassert_equal(rc, 1);
298 	zassert_equal(k_work_busy_get(&common_work), K_WORK_QUEUED);
299 	zassert_equal(k_work_is_pending(&common_work), true);
300 
301 	/* Shouldn't have been started since test thread is
302 	 * cooperative.
303 	 */
304 	zassert_equal(coophi_counter(), 0);
305 
306 	/* Let it run, then check it finished. */
307 	k_sleep(K_TICKS(1));
308 	zassert_equal(coophi_counter(), 1);
309 	zassert_equal(k_work_busy_get(&common_work), 0);
310 
311 	/* Flush the sync state from completion */
312 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
313 	zassert_equal(rc, 0);
314 }
315 
316 /* Basic SMP check submitting with a non-blocking handler. */
ZTEST(work,test_smp_simple_queue)317 ZTEST(work, test_smp_simple_queue)
318 {
319 	if (!IS_ENABLED(CONFIG_SMP)) {
320 		ztest_test_skip();
321 		return;
322 	}
323 
324 	int rc;
325 
326 	/* Reset state and use the non-blocking handler */
327 	reset_counters();
328 	k_work_init(&common_work, counter_handler);
329 	zassert_equal(k_work_busy_get(&common_work), 0);
330 	zassert_equal(k_work_is_pending(&common_work), false);
331 
332 	/* Submit to the cooperative queue */
333 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
334 	zassert_equal(rc, 1);
335 
336 	/* It should run and finish without this thread yielding. */
337 	int64_t ts0 = k_uptime_ticks();
338 	uint32_t delay;
339 
340 	do {
341 		delay = k_ticks_to_ms_floor32(k_uptime_ticks() - ts0);
342 	} while (k_work_is_pending(&common_work) && (delay < DELAY_MS));
343 
344 	zassert_equal(k_work_busy_get(&common_work), 0);
345 	zassert_equal(coophi_counter(), 1);
346 
347 	/* Flush the sync state from completion */
348 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
349 	zassert_equal(rc, 0);
350 }
351 
352 /* Basic single-CPU check submitting with a blocking handler */
ZTEST(work_1cpu,test_1cpu_sync_queue)353 ZTEST(work_1cpu, test_1cpu_sync_queue)
354 {
355 	int rc;
356 
357 	/* Reset state and use the blocking handler */
358 	reset_counters();
359 	k_work_init(&common_work, rel_handler);
360 	zassert_equal(k_work_busy_get(&common_work), 0);
361 
362 	/* Submit to the cooperative queue */
363 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
364 	zassert_equal(rc, 1);
365 	zassert_equal(k_work_busy_get(&common_work), K_WORK_QUEUED);
366 
367 	/* Shouldn't have been started since test thread is
368 	 * cooperative.
369 	 */
370 	zassert_equal(coophi_counter(), 0);
371 
372 	/* Let it run, then check it didn't finish. */
373 	k_sleep(K_TICKS(1));
374 	zassert_equal(coophi_counter(), 0);
375 	zassert_equal(k_work_busy_get(&common_work), K_WORK_RUNNING);
376 
377 	/* Make it ready so it can finish when this thread yields. */
378 	handler_release();
379 	zassert_equal(coophi_counter(), 0);
380 
381 	/* Wait for then verify finish */
382 	rc = k_sem_take(&sync_sem, K_FOREVER);
383 	zassert_equal(rc, 0);
384 	zassert_equal(coophi_counter(), 1);
385 }
386 
387 /* Verify that if a work item is submitted while it is being run by a
388  * queue thread it gets submitted to the queue it's running on, to
389  * prevent reentrant invocation, at least on a single CPU.
390  */
ZTEST(work_1cpu,test_1cpu_reentrant_queue)391 ZTEST(work_1cpu, test_1cpu_reentrant_queue)
392 {
393 	int rc;
394 
395 	/* Reset state and use the blocking handler */
396 	reset_counters();
397 	k_work_init(&common_work, rel_handler);
398 
399 	/* Submit to the cooperative queue. */
400 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
401 	zassert_equal(rc, 1);
402 	zassert_equal(coophi_counter(), 0);
403 
404 	/* Release it so it's running and can be rescheduled. */
405 	k_sleep(K_TICKS(1));
406 	zassert_equal(coophi_counter(), 0);
407 
408 	/* Resubmit to a different queue. */
409 	rc = k_work_submit_to_queue(&preempt_queue, &common_work);
410 	zassert_equal(rc, 2);
411 
412 	/* Release the first submission. */
413 	handler_release();
414 	rc = k_sem_take(&sync_sem, K_FOREVER);
415 	zassert_equal(rc, 0);
416 	zassert_equal(coophi_counter(), 1);
417 
418 	/* Confirm the second submission was redirected to the running
419 	 * queue to avoid re-entrancy problems.
420 	 */
421 	handler_release();
422 	rc = k_sem_take(&sync_sem, K_FOREVER);
423 	zassert_equal(rc, 0);
424 	zassert_equal(coophi_counter(), 2);
425 }
426 
427 /* Single CPU submit two work items and wait for flush in order
428  * before they get started.
429  */
ZTEST(work_1cpu,test_1cpu_queued_flush)430 ZTEST(work_1cpu, test_1cpu_queued_flush)
431 {
432 	int rc;
433 
434 	/* Reset state and use the delaying handler */
435 	reset_counters();
436 	k_work_init(&common_work, delay_handler);
437 	k_work_init(&common_work1, delay_handler);
438 
439 	/* Submit to the cooperative queue. */
440 	rc = k_work_submit_to_queue(&coophi_queue, &common_work1);
441 	zassert_equal(rc, 1);
442 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
443 	zassert_equal(rc, 1);
444 	zassert_equal(coophi_counter(), 0);
445 
446 	/* Confirm that it's still in the queue, then wait for completion.
447 	 * This should wait.
448 	 */
449 	zassert_equal(k_work_busy_get(&common_work), K_WORK_QUEUED);
450 	zassert_equal(k_work_busy_get(&common_work1), K_WORK_QUEUED);
451 	zassert_true(k_work_flush(&common_work, &work_sync));
452 	zassert_false(k_work_flush(&common_work1, &work_sync));
453 
454 	/* Verify completion. */
455 	zassert_equal(coophi_counter(), 2);
456 	zassert_true(!k_work_is_pending(&common_work));
457 	zassert_true(!k_work_is_pending(&common_work1));
458 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
459 	zassert_equal(rc, 0);
460 
461 	/* After completion flush should be a no-op */
462 	zassert_false(k_work_flush(&common_work, &work_sync));
463 	zassert_false(k_work_flush(&common_work1, &work_sync));
464 }
465 
466 /* Single CPU submit a work item and wait for flush after it's started.
467  */
ZTEST(work_1cpu,test_1cpu_running_flush)468 ZTEST(work_1cpu, test_1cpu_running_flush)
469 {
470 	int rc;
471 
472 	/* Reset state and use the delaying handler */
473 	reset_counters();
474 	k_work_init(&common_work, delay_handler);
475 
476 	/* Submit to the cooperative queue. */
477 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
478 	zassert_equal(rc, 1);
479 	zassert_equal(coophi_counter(), 0);
480 	zassert_equal(k_work_busy_get(&common_work), K_WORK_QUEUED);
481 
482 	/* Release it so it's running. */
483 	k_sleep(K_TICKS(1));
484 	zassert_equal(k_work_busy_get(&common_work), K_WORK_RUNNING);
485 	zassert_equal(coophi_counter(), 0);
486 
487 	/* Wait for completion.  This should be released by the delay
488 	 * handler.
489 	 */
490 	zassert_true(k_work_flush(&common_work, &work_sync));
491 
492 	/* Verify completion. */
493 	zassert_equal(coophi_counter(), 1);
494 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
495 	zassert_equal(rc, 0);
496 }
497 
498 /* Single CPU schedule a work item and wait for flush. */
ZTEST(work_1cpu,test_1cpu_delayed_flush)499 ZTEST(work_1cpu, test_1cpu_delayed_flush)
500 {
501 	int rc;
502 	uint32_t flush_ms;
503 	uint32_t wait_ms;
504 
505 	/* Reset state and use non-blocking handler */
506 	reset_counters();
507 	k_work_init_delayable(&dwork, counter_handler);
508 
509 	/* Unscheduled completes immediately. */
510 	zassert_false(k_work_flush_delayable(&dwork, &work_sync));
511 
512 	/* Submit to the cooperative queue. */
513 	rc = k_work_schedule_for_queue(&coophi_queue, &dwork, K_MSEC(DELAY_MS));
514 	zassert_equal(rc, 1);
515 	zassert_equal(coophi_counter(), 0);
516 
517 	/* Align to tick then flush. */
518 	k_sleep(K_TICKS(1));
519 	flush_ms = k_uptime_get_32();
520 	zassert_true(k_work_flush_delayable(&dwork, &work_sync));
521 	wait_ms = last_handle_ms - flush_ms;
522 	zassert_true(wait_ms <= 1, "waited %u", wait_ms);
523 
524 	/* Verify completion. */
525 	zassert_equal(coophi_counter(), 1);
526 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
527 	zassert_equal(rc, 0);
528 }
529 
530 /* Single CPU cancel before work item is unqueued should complete
531  * immediately.
532  */
ZTEST(work_1cpu,test_1cpu_queued_cancel)533 ZTEST(work_1cpu, test_1cpu_queued_cancel)
534 {
535 	int rc;
536 
537 	/* Reset state and use the blocking handler */
538 	reset_counters();
539 	k_work_init(&common_work, rel_handler);
540 
541 	/* Submit to the cooperative queue. */
542 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
543 	zassert_equal(rc, 1);
544 	zassert_equal(coophi_counter(), 0);
545 
546 	/* Cancellation should complete immediately. */
547 	zassert_equal(k_work_cancel(&common_work), 0);
548 
549 	/* Shouldn't have run. */
550 	zassert_equal(coophi_counter(), 0);
551 }
552 
553 /* Single CPU cancel before work item is unqueued should not wait. */
ZTEST(work_1cpu,test_1cpu_queued_cancel_sync)554 ZTEST(work_1cpu, test_1cpu_queued_cancel_sync)
555 {
556 	int rc;
557 
558 	/* Reset state and use the blocking handler */
559 	reset_counters();
560 	k_work_init(&common_work, rel_handler);
561 
562 	/* Cancel an unqueued work item should not affect the work
563 	 * and return false.
564 	 */
565 	zassert_false(k_work_cancel_sync(&common_work, &work_sync));
566 
567 	/* Submit to the cooperative queue. */
568 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
569 	zassert_equal(rc, 1);
570 	zassert_equal(coophi_counter(), 0);
571 
572 	/* Cancellation should complete immediately, indicating that
573 	 * work was pending.
574 	 */
575 	zassert_true(k_work_cancel_sync(&common_work, &work_sync));
576 
577 	/* Shouldn't have run. */
578 	zassert_equal(coophi_counter(), 0);
579 }
580 
581 /* Single CPU cancel before scheduled work item is queued should
582  * complete immediately.
583  */
ZTEST(work_1cpu,test_1cpu_delayed_cancel)584 ZTEST(work_1cpu, test_1cpu_delayed_cancel)
585 {
586 	int rc;
587 
588 	/* Reset state and use the blocking handler */
589 	reset_counters();
590 	k_work_init_delayable(&dwork, rel_handler);
591 
592 	/* Submit to the cooperative queue. */
593 	rc = k_work_schedule_for_queue(&coophi_queue, &dwork, K_MSEC(DELAY_MS));
594 	zassert_equal(rc, 1);
595 	zassert_equal(coophi_counter(), 0);
596 
597 	/* Cancellation should complete immediately. */
598 	zassert_equal(k_work_cancel_delayable(&dwork), 0);
599 
600 	/* Shouldn't have run. */
601 	zassert_equal(coophi_counter(), 0);
602 }
603 
604 
605 /* Single CPU cancel before scheduled work item is queued should not wait. */
ZTEST(work_1cpu,test_1cpu_delayed_cancel_sync)606 ZTEST(work_1cpu, test_1cpu_delayed_cancel_sync)
607 {
608 	int rc;
609 
610 	/* Reset state and use the blocking handler */
611 	reset_counters();
612 	k_work_init_delayable(&dwork, rel_handler);
613 
614 	/* Cancel an unqueued delayable work item should not affect the work
615 	 * and return false.
616 	 */
617 	zassert_false(k_work_cancel_delayable_sync(&dwork, &work_sync));
618 
619 	/* Submit to the cooperative queue. */
620 	rc = k_work_schedule_for_queue(&coophi_queue, &dwork, K_MSEC(DELAY_MS));
621 	zassert_equal(rc, 1);
622 	zassert_equal(coophi_counter(), 0);
623 
624 	/* Cancellation should complete immediately, indicating that
625 	 * work was pending.
626 	 */
627 	zassert_true(k_work_cancel_delayable_sync(&dwork, &work_sync));
628 
629 	/* Shouldn't have run. */
630 	zassert_equal(coophi_counter(), 0);
631 }
632 
633 /* Single CPU cancel after delayable item starts should wait. */
ZTEST(work_1cpu,test_1cpu_delayed_cancel_sync_wait)634 ZTEST(work_1cpu, test_1cpu_delayed_cancel_sync_wait)
635 {
636 	int rc;
637 
638 	/* Reset state and use the blocking handler */
639 	reset_counters();
640 	k_work_init_delayable(&dwork, rel_handler);
641 
642 	/* Submit to the cooperative queue. */
643 	rc = k_work_schedule_for_queue(&coophi_queue, &dwork, K_NO_WAIT);
644 	zassert_equal(k_work_delayable_busy_get(&dwork), K_WORK_QUEUED);
645 	zassert_equal(coophi_counter(), 0);
646 
647 	/* Get it to running, where it will block. */
648 	k_sleep(K_TICKS(1));
649 	zassert_equal(coophi_counter(), 0);
650 	zassert_equal(k_work_delayable_busy_get(&dwork), K_WORK_RUNNING);
651 
652 	/* Schedule to release, then cancel should delay. */
653 	async_release();
654 	zassert_true(k_work_cancel_delayable_sync(&dwork, &work_sync));
655 
656 	/* Verify completion. */
657 	zassert_equal(coophi_counter(), 1);
658 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
659 	zassert_equal(rc, 0);
660 }
661 
662 /* Infrastructure to capture behavior of work item that's being
663  * cancelled.
664  */
665 struct test_running_cancel_timer {
666 	struct k_timer timer;
667 	struct k_work work;
668 	int submit_rc;
669 	int busy_rc;
670 };
671 
672 static struct test_running_cancel_timer test_running_cancel_ctx;
673 
test_running_cancel_cb(struct k_timer * timer)674 static void test_running_cancel_cb(struct k_timer *timer)
675 {
676 	struct test_running_cancel_timer *ctx =
677 		CONTAINER_OF(timer, struct test_running_cancel_timer, timer);
678 
679 	ctx->busy_rc = k_work_busy_get(&ctx->work);
680 	ctx->submit_rc = k_work_submit_to_queue(&coophi_queue, &ctx->work);
681 	handler_release();
682 }
683 
684 /* Single CPU test cancellation after work starts. */
ZTEST(work_1cpu,test_1cpu_running_cancel)685 ZTEST(work_1cpu, test_1cpu_running_cancel)
686 {
687 	struct test_running_cancel_timer *ctx = &test_running_cancel_ctx;
688 	struct k_work *wp = &ctx->work;
689 	static const uint32_t ms_timeout = 10;
690 	int rc;
691 
692 	/* Reset state and use the blocking handler */
693 	reset_counters();
694 	k_work_init(wp, rel_handler);
695 
696 	/* Submit to the cooperative queue. */
697 	rc = k_work_submit_to_queue(&coophi_queue, wp);
698 	zassert_equal(rc, 1);
699 	zassert_equal(coophi_counter(), 0);
700 
701 	/* Release it so it's running. */
702 	k_sleep(K_TICKS(1));
703 	zassert_equal(coophi_counter(), 0);
704 
705 	/* Schedule the async process to capture state and release work. */
706 	ctx->submit_rc = INT_MAX;
707 	ctx->busy_rc = INT_MAX;
708 	k_timer_init(&ctx->timer, test_running_cancel_cb, NULL);
709 	k_timer_start(&ctx->timer, K_MSEC(ms_timeout), K_NO_WAIT);
710 
711 	/* Cancellation should not complete. */
712 	zassert_equal(k_work_cancel(wp), K_WORK_RUNNING | K_WORK_CANCELING,
713 		      NULL);
714 
715 	/* Handler should not have run. */
716 	zassert_equal(coophi_counter(), 0);
717 
718 	/* Busy wait until timer expires. Thread context is blocked so cancelling
719 	 * of work won't be completed.
720 	 */
721 	k_busy_wait(1000 * (ms_timeout + 1));
722 
723 	zassert_equal(k_timer_status_get(&ctx->timer), 1);
724 
725 	/* Wait for cancellation to complete. */
726 	zassert_true(k_work_cancel_sync(wp, &work_sync));
727 
728 	/* Verify completion */
729 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
730 	zassert_equal(rc, 0);
731 
732 	/* Handler should have detected running and canceling. */
733 	zassert_equal(ctx->busy_rc, K_WORK_RUNNING | K_WORK_CANCELING);
734 
735 	/* Attempt to submit while cancelling should have been
736 	 * rejected.
737 	 */
738 	zassert_equal(ctx->submit_rc, -EBUSY);
739 
740 	/* Post-cancellation should have no flags. */
741 	rc = k_work_busy_get(wp);
742 	zassert_equal(rc, 0, "bad: %d", rc);
743 }
744 
745 /* Single CPU test wait-for-cancellation after the work item has
746  * started running.
747  */
ZTEST(work_1cpu,test_1cpu_running_cancel_sync)748 ZTEST(work_1cpu, test_1cpu_running_cancel_sync)
749 {
750 	struct test_running_cancel_timer *ctx = &test_running_cancel_ctx;
751 	struct k_work *wp = &ctx->work;
752 	static const uint32_t ms_timeout = 10;
753 	int rc;
754 
755 	/* Reset state and use the blocking handler */
756 	reset_counters();
757 	k_work_init(wp, rel_handler);
758 
759 	/* Submit to the cooperative queue. */
760 	rc = k_work_submit_to_queue(&coophi_queue, wp);
761 	zassert_equal(rc, 1);
762 	zassert_equal(coophi_counter(), 0);
763 
764 	/* Release it so it's running. */
765 	k_sleep(K_TICKS(1));
766 	zassert_equal(coophi_counter(), 0);
767 
768 	/* Schedule the async process to capture state and release work. */
769 	ctx->submit_rc = INT_MAX;
770 	ctx->busy_rc = INT_MAX;
771 	k_timer_init(&ctx->timer, test_running_cancel_cb, NULL);
772 	k_timer_start(&ctx->timer, K_MSEC(ms_timeout), K_NO_WAIT);
773 
774 	/* Cancellation should wait. */
775 	zassert_true(k_work_cancel_sync(wp, &work_sync));
776 
777 	/* Handler should have run. */
778 	zassert_equal(coophi_counter(), 1);
779 
780 	/* Busy wait until timer expires. Thread context is blocked so cancelling
781 	 * of work won't be completed.
782 	 */
783 	k_busy_wait(1000 * (ms_timeout + 1));
784 
785 	zassert_equal(k_timer_status_get(&ctx->timer), 1);
786 
787 	/* Verify completion */
788 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
789 	zassert_equal(rc, 0);
790 
791 	/* Handler should have detected running and canceling. */
792 	zassert_equal(ctx->busy_rc, K_WORK_RUNNING | K_WORK_CANCELING,
793 		      NULL);
794 
795 	/* Attempt to submit while cancelling should have been
796 	 * rejected.
797 	 */
798 	zassert_equal(ctx->submit_rc, -EBUSY);
799 
800 	/* Post-cancellation should have no flags. */
801 	rc = k_work_busy_get(wp);
802 	zassert_equal(rc, 0, "bad: %d", rc);
803 }
804 
805 /* SMP cancel after work item is started should succeed but require
806  * wait.
807  */
ZTEST(work,test_smp_running_cancel)808 ZTEST(work, test_smp_running_cancel)
809 {
810 	int rc;
811 
812 	if (!IS_ENABLED(CONFIG_SMP)) {
813 		ztest_test_skip();
814 		return;
815 	}
816 
817 	/* Reset state and use the delaying handler */
818 	reset_counters();
819 	k_work_init(&common_work, delay_handler);
820 
821 	/* Submit to the cooperative queue. */
822 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
823 	zassert_equal(rc, 1);
824 
825 	/* It should advance to running without this thread yielding. */
826 	int64_t ts0 = k_uptime_ticks();
827 	uint32_t delay;
828 
829 	do {
830 		delay = k_ticks_to_ms_floor32(k_uptime_ticks() - ts0);
831 	} while ((k_work_busy_get(&common_work) != K_WORK_RUNNING)
832 		 && (delay < DELAY_MS));
833 
834 	/* Cancellation should not succeed immediately because the
835 	 * work is running.
836 	 */
837 	rc = k_work_cancel(&common_work);
838 	zassert_equal(rc, K_WORK_RUNNING | K_WORK_CANCELING, "rc %x", rc);
839 
840 	/* Sync should wait. */
841 	zassert_equal(k_work_cancel_sync(&common_work, &work_sync), true);
842 
843 	/* Should have completed. */
844 	zassert_equal(coophi_counter(), 1);
845 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
846 	zassert_equal(rc, 0);
847 }
848 
849 /* Drain with no active workers completes immediately. */
ZTEST(work,test_drain_empty)850 ZTEST(work, test_drain_empty)
851 {
852 	int rc;
853 
854 	rc = k_work_queue_drain(&coophi_queue, false);
855 	zassert_equal(rc, 0);
856 }
857 
858 struct test_drain_wait_timer {
859 	struct k_timer timer;
860 	struct k_work work;
861 	int submit_rc;
862 };
863 
864 static struct test_drain_wait_timer test_drain_wait_ctx;
865 
test_drain_wait_cb(struct k_timer * timer)866 static void test_drain_wait_cb(struct k_timer *timer)
867 {
868 	struct test_drain_wait_timer *ctx =
869 		CONTAINER_OF(timer, struct test_drain_wait_timer, timer);
870 
871 	ctx->submit_rc = k_work_submit_to_queue(&coophi_queue, &ctx->work);
872 }
873 
874 /* Single CPU submit an item and wait for it to drain. */
ZTEST(work_1cpu,test_1cpu_drain_wait)875 ZTEST(work_1cpu, test_1cpu_drain_wait)
876 {
877 	struct test_drain_wait_timer *ctx = &test_drain_wait_ctx;
878 	struct k_work *wp = &ctx->work;
879 	int rc;
880 
881 	/* Reset state, allow one re-submission, and use the delaying
882 	 * handler.
883 	 */
884 	reset_counters();
885 	atomic_set(&resubmits_left, 1);
886 	k_work_init(wp, delay_handler);
887 
888 	/* Submit to the cooperative queue. */
889 	rc = k_work_submit_to_queue(&coophi_queue, wp);
890 	zassert_equal(rc, 1);
891 	zassert_equal(coophi_counter(), 0);
892 
893 	/* Schedule the async process to capture submission state
894 	 * while draining.
895 	 */
896 	ctx->submit_rc = INT_MAX;
897 	k_timer_init(&ctx->timer, test_drain_wait_cb, NULL);
898 	k_timer_start(&ctx->timer, K_MSEC(10), K_NO_WAIT);
899 
900 	/* Wait to drain */
901 	rc = k_work_queue_drain(&coophi_queue, false);
902 	zassert_equal(rc, 1);
903 
904 	/* Wait until timer expires. */
905 	(void)k_timer_status_sync(&ctx->timer);
906 
907 	/* Verify completion */
908 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
909 	zassert_equal(rc, 0);
910 
911 	/* Confirm that chained submission worked, and non-chained
912 	 * submission failed.
913 	 */
914 	zassert_equal(coophi_counter(), 2);
915 	zassert_equal(ctx->submit_rc, -EBUSY);
916 }
917 
918 /* Single CPU submit item, drain with plug, test, then unplug. */
ZTEST(work_1cpu,test_1cpu_plugged_drain)919 ZTEST(work_1cpu, test_1cpu_plugged_drain)
920 {
921 	int rc;
922 
923 	/* Reset state and use the delaying handler. */
924 	reset_counters();
925 	k_work_init(&common_work, delay_handler);
926 
927 	/* Submit to the cooperative queue */
928 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
929 	zassert_equal(rc, 1);
930 
931 	/* Wait to drain, and plug. */
932 	rc = k_work_queue_drain(&coophi_queue, true);
933 	zassert_equal(rc, 1);
934 
935 	/* Verify completion */
936 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
937 	zassert_equal(rc, 0);
938 	zassert_equal(coophi_counter(), 1);
939 
940 	/* Queue should be plugged */
941 	zassert_equal(coophi_queue.flags,
942 		      K_WORK_QUEUE_STARTED
943 		      | K_WORK_QUEUE_PLUGGED
944 		      | K_WORK_QUEUE_NO_YIELD,
945 		      NULL);
946 
947 	/* Switch to the non-blocking handler. */
948 	k_work_init(&common_work, counter_handler);
949 
950 	/* Resubmission should fail because queue is plugged */
951 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
952 	zassert_equal(rc, -EBUSY);
953 
954 	/* Unplug the queue */
955 	rc = k_work_queue_unplug(&coophi_queue);
956 	zassert_equal(rc, 0);
957 
958 	/* Unplug the unplugged queue should not affect the queue */
959 	rc = k_work_queue_unplug(&coophi_queue);
960 	zassert_equal(rc, -EALREADY);
961 	zassert_equal(coophi_queue.flags,
962 		      K_WORK_QUEUE_STARTED | K_WORK_QUEUE_NO_YIELD,
963 		      NULL);
964 
965 	/* Resubmission should succeed and complete */
966 	rc = k_work_submit_to_queue(&coophi_queue, &common_work);
967 	zassert_equal(rc, 1);
968 
969 	/* Flush the sync state and verify completion */
970 	rc = k_sem_take(&sync_sem, K_FOREVER);
971 	zassert_equal(rc, 0);
972 	zassert_equal(coophi_counter(), 2);
973 }
974 
975 /* Single CPU test delayed submission */
ZTEST(work_1cpu,test_1cpu_basic_schedule)976 ZTEST(work_1cpu, test_1cpu_basic_schedule)
977 {
978 	int rc;
979 	uint32_t sched_ms;
980 	uint32_t max_ms = k_ticks_to_ms_ceil32(1U
981 				+ k_ms_to_ticks_ceil32(DELAY_MS));
982 	uint32_t elapsed_ms;
983 	struct k_work *wp = &dwork.work; /* whitebox testing */
984 
985 	/* Reset state and use non-blocking handler */
986 	reset_counters();
987 	k_work_init_delayable(&dwork, counter_handler);
988 
989 	/* Verify that work is idle and marked delayable. */
990 	zassert_equal(k_work_busy_get(wp), 0);
991 	zassert_equal(wp->flags & K_WORK_DELAYABLE, K_WORK_DELAYABLE,
992 		       NULL);
993 
994 	/* Align to tick, then schedule after normal delay. */
995 	k_sleep(K_TICKS(1));
996 	sched_ms = k_uptime_get_32();
997 	rc = k_work_schedule_for_queue(&coophi_queue, &dwork, K_MSEC(DELAY_MS));
998 	zassert_equal(rc, 1);
999 	rc = k_work_busy_get(wp);
1000 	zassert_equal(rc, K_WORK_DELAYED);
1001 	zassert_equal(k_work_delayable_busy_get(&dwork), rc);
1002 	zassert_equal(k_work_delayable_is_pending(&dwork), true);
1003 
1004 	/* Scheduling again does nothing. */
1005 	rc = k_work_schedule_for_queue(&coophi_queue, &dwork, K_NO_WAIT);
1006 	zassert_equal(rc, 0);
1007 
1008 	/* Wait for completion */
1009 	rc = k_sem_take(&sync_sem, K_FOREVER);
1010 	zassert_equal(rc, 0);
1011 
1012 	/* Make sure it ran and is now idle */
1013 	zassert_equal(coophi_counter(), 1);
1014 	zassert_equal(k_work_busy_get(wp), 0);
1015 
1016 	/* Check that the delay is within the expected range. */
1017 	elapsed_ms = last_handle_ms - sched_ms;
1018 	zassert_true(elapsed_ms >= DELAY_MS,
1019 		     "short %u < %u\n", elapsed_ms, DELAY_MS);
1020 	zassert_true(elapsed_ms <= max_ms,
1021 		     "long %u > %u\n", elapsed_ms, max_ms);
1022 }
1023 
1024 struct state_1cpu_basic_schedule_running {
1025 	struct k_work_delayable dwork;
1026 	int schedule_res;
1027 };
1028 
handle_1cpu_basic_schedule_running(struct k_work * work)1029 static void handle_1cpu_basic_schedule_running(struct k_work *work)
1030 {
1031 	struct k_work_delayable *one_dwork = k_work_delayable_from_work(work);
1032 	struct state_1cpu_basic_schedule_running *state
1033 		= CONTAINER_OF(one_dwork, struct state_1cpu_basic_schedule_running,
1034 			       dwork);
1035 
1036 	/* Co-opt the resubmits so we can test the schedule API
1037 	 * explicitly.
1038 	 */
1039 	if (atomic_dec(&resubmits_left) > 0) {
1040 		/* Schedule again on current queue */
1041 		state->schedule_res = k_work_schedule_for_queue(NULL, one_dwork,
1042 								K_MSEC(DELAY_MS));
1043 	} else {
1044 		/* Flag that it didn't schedule */
1045 		state->schedule_res = -EALREADY;
1046 	}
1047 
1048 	counter_handler(work);
1049 }
1050 
1051 /* Single CPU test that schedules when running */
ZTEST(work_1cpu,test_1cpu_basic_schedule_running)1052 ZTEST(work_1cpu, test_1cpu_basic_schedule_running)
1053 {
1054 	int rc;
1055 	static struct state_1cpu_basic_schedule_running state = {
1056 		.schedule_res = -1,
1057 	};
1058 
1059 	/* Reset state and set for one resubmit.  Use a test-specific
1060 	 * handler.
1061 	 */
1062 	reset_counters();
1063 	atomic_set(&resubmits_left, 1);
1064 	k_work_init_delayable(&state.dwork, handle_1cpu_basic_schedule_running);
1065 
1066 	zassert_equal(state.schedule_res, -1);
1067 
1068 	rc = k_work_schedule_for_queue(&coophi_queue, &state.dwork,
1069 				       K_MSEC(DELAY_MS));
1070 	zassert_equal(rc, 1);
1071 
1072 	zassert_equal(coop_counter(&coophi_queue), 0);
1073 
1074 	/* Wait for completion */
1075 	rc = k_sem_take(&sync_sem, K_FOREVER);
1076 	zassert_equal(rc, 0);
1077 	zassert_equal(state.schedule_res, 1);
1078 	zassert_equal(coop_counter(&coophi_queue), 1);
1079 
1080 	/* Wait for completion */
1081 	rc = k_sem_take(&sync_sem, K_FOREVER);
1082 	zassert_equal(rc, 0);
1083 	zassert_equal(state.schedule_res, -EALREADY);
1084 	zassert_equal(coop_counter(&coophi_queue), 2);
1085 }
1086 
1087 /* Single CPU test schedule without delay is queued immediately. */
ZTEST(work_1cpu,test_1cpu_immed_schedule)1088 ZTEST(work_1cpu, test_1cpu_immed_schedule)
1089 {
1090 	int rc;
1091 	struct k_work *wp = &dwork.work; /* whitebox testing */
1092 
1093 	/* Reset state and use the non-blocking handler */
1094 	reset_counters();
1095 	k_work_init_delayable(&dwork, counter_handler);
1096 	zassert_equal(k_work_busy_get(wp), 0);
1097 
1098 	/* Submit to the cooperative queue */
1099 	rc = k_work_schedule_for_queue(&coophi_queue, &dwork, K_NO_WAIT);
1100 	zassert_equal(rc, 1);
1101 	rc = k_work_busy_get(wp);
1102 	zassert_equal(rc, K_WORK_QUEUED);
1103 	zassert_equal(k_work_delayable_busy_get(&dwork), rc);
1104 	zassert_equal(k_work_delayable_is_pending(&dwork), true);
1105 
1106 	/* Scheduling again does nothing. */
1107 	rc = k_work_schedule_for_queue(&coophi_queue, &dwork, K_NO_WAIT);
1108 	zassert_equal(rc, 0);
1109 
1110 	/* Shouldn't have been started since test thread is
1111 	 * cooperative.
1112 	 */
1113 	zassert_equal(coophi_counter(), 0);
1114 
1115 	/* Let it run, then check it didn't finish. */
1116 	k_sleep(K_TICKS(1));
1117 	zassert_equal(coophi_counter(), 1);
1118 	zassert_equal(k_work_busy_get(wp), 0);
1119 
1120 	/* Flush the sync state from completion */
1121 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
1122 	zassert_equal(rc, 0);
1123 }
1124 
1125 /* Single CPU test that delayed work can be rescheduled. */
ZTEST(work_1cpu,test_1cpu_basic_reschedule)1126 ZTEST(work_1cpu, test_1cpu_basic_reschedule)
1127 {
1128 	int rc;
1129 	uint32_t sched_ms;
1130 	uint32_t max_ms = k_ticks_to_ms_ceil32(1U
1131 				+ k_ms_to_ticks_ceil32(DELAY_MS));
1132 	uint32_t elapsed_ms;
1133 	struct k_work *wp = &dwork.work; /* whitebox testing */
1134 
1135 	/* Reset state and use non-blocking handler */
1136 	reset_counters();
1137 	k_work_init_delayable(&dwork, counter_handler);
1138 
1139 	/* Verify that work is idle and marked delayable. */
1140 	zassert_equal(k_work_busy_get(wp), 0);
1141 	zassert_equal(wp->flags & K_WORK_DELAYABLE, K_WORK_DELAYABLE,
1142 		       NULL);
1143 
1144 	/* Schedule to the preempt queue after twice the standard
1145 	 * delay.
1146 	 */
1147 	rc = k_work_reschedule_for_queue(&preempt_queue, &dwork,
1148 					  K_MSEC(2U * DELAY_MS));
1149 	zassert_equal(rc, 1);
1150 	zassert_equal(k_work_busy_get(wp), K_WORK_DELAYED);
1151 
1152 	/* Align to tick then reschedule on the cooperative queue for
1153 	 * the standard delay.
1154 	 */
1155 	k_sleep(K_TICKS(1));
1156 	sched_ms = k_uptime_get_32();
1157 	rc = k_work_reschedule_for_queue(&coophi_queue, &dwork,
1158 					  K_MSEC(DELAY_MS));
1159 	zassert_equal(rc, 1);
1160 	zassert_equal(k_work_busy_get(wp), K_WORK_DELAYED);
1161 
1162 	/* Wait for completion */
1163 	rc = k_sem_take(&sync_sem, K_FOREVER);
1164 	zassert_equal(rc, 0);
1165 
1166 	/* Make sure it ran on the coop queue and is now idle */
1167 	zassert_equal(coophi_counter(), 1);
1168 	zassert_equal(k_work_busy_get(wp), 0);
1169 
1170 	/* Check that the delay is within the expected range. */
1171 	elapsed_ms = last_handle_ms - sched_ms;
1172 	zassert_true(elapsed_ms >= DELAY_MS,
1173 		     "short %u < %u\n", elapsed_ms, DELAY_MS);
1174 	zassert_true(elapsed_ms <= max_ms,
1175 		     "long %u > %u\n", elapsed_ms, max_ms);
1176 }
1177 
1178 /* Single CPU test that delayed work can be immediately queued by
1179  * reschedule API.
1180  */
ZTEST(work_1cpu,test_1cpu_immed_reschedule)1181 ZTEST(work_1cpu, test_1cpu_immed_reschedule)
1182 {
1183 	int rc;
1184 	struct k_work *wp = &dwork.work; /* whitebox testing */
1185 
1186 	/* Reset state and use the delay handler */
1187 	reset_counters();
1188 	k_work_init_delayable(&dwork, delay_handler);
1189 	zassert_equal(k_work_busy_get(wp), 0);
1190 
1191 	/* Schedule immediately to the cooperative queue */
1192 	rc = k_work_reschedule_for_queue(&coophi_queue, &dwork, K_NO_WAIT);
1193 	zassert_equal(rc, 1);
1194 	zassert_equal(k_work_busy_get(wp), K_WORK_QUEUED);
1195 
1196 	/* Shouldn't have been started since test thread is
1197 	 * cooperative.
1198 	 */
1199 	zassert_equal(coophi_counter(), 0);
1200 
1201 	/* Let it run, then check it didn't finish. */
1202 	k_sleep(K_TICKS(1));
1203 	zassert_equal(coophi_counter(), 0);
1204 	zassert_equal(k_work_busy_get(wp), K_WORK_RUNNING);
1205 
1206 	/* Schedule immediately to the preemptive queue (will divert
1207 	 * to coop since running).
1208 	 */
1209 	rc = k_work_reschedule_for_queue(&preempt_queue, &dwork, K_NO_WAIT);
1210 	zassert_equal(rc, 2);
1211 	zassert_equal(k_work_busy_get(wp), K_WORK_QUEUED | K_WORK_RUNNING,
1212 		      NULL);
1213 
1214 	/* Schedule after 3x the delay to the preemptive queue
1215 	 * (will not divert since previous submissions will have
1216 	 * completed).
1217 	 */
1218 	rc = k_work_reschedule_for_queue(&preempt_queue, &dwork,
1219 					  K_MSEC(3 * DELAY_MS));
1220 	zassert_equal(rc, 1);
1221 	zassert_equal(k_work_busy_get(wp),
1222 		      K_WORK_DELAYED | K_WORK_QUEUED | K_WORK_RUNNING,
1223 		      NULL);
1224 
1225 	/* Wait for the original no-wait submission (total 1 delay)) */
1226 	rc = k_sem_take(&sync_sem, K_FOREVER);
1227 	zassert_equal(rc, 0);
1228 
1229 	/* Check that coop ran once, and work is still delayed and
1230 	 * also running.
1231 	 */
1232 	zassert_equal(coophi_counter(), 1);
1233 	zassert_equal(k_work_busy_get(wp), K_WORK_DELAYED | K_WORK_RUNNING,
1234 		      NULL);
1235 
1236 	/* Wait for the queued no-wait submission (total 2 delay) */
1237 	rc = k_sem_take(&sync_sem, K_FOREVER);
1238 	zassert_equal(rc, 0);
1239 
1240 	/* Check that got diverted to coop and ran, and work is still
1241 	 * delayed.
1242 	 */
1243 	zassert_equal(coophi_counter(), 2);
1244 	zassert_equal(preempt_counter(), 0);
1245 	zassert_equal(k_work_busy_get(wp), K_WORK_DELAYED,
1246 		      NULL);
1247 
1248 	/* Wait for the delayed submission (total 3 delay) */
1249 	rc = k_sem_take(&sync_sem, K_FOREVER);
1250 	zassert_equal(rc, 0);
1251 
1252 	/* Check that ran on preempt.  In fact we're here because the
1253 	 * test thread is higher priority, so the work will still be
1254 	 * marked running.
1255 	 */
1256 	zassert_equal(coophi_counter(), 2);
1257 	zassert_equal(preempt_counter(), 1);
1258 	zassert_equal(k_work_busy_get(wp), K_WORK_RUNNING,
1259 		      NULL);
1260 
1261 	/* Wait for preempt to drain */
1262 	rc = k_work_queue_drain(&preempt_queue, false);
1263 	zassert_equal(rc, 1);
1264 }
1265 
1266 /* Test no-yield behavior, returns true if and only if work queue priority is
1267  * higher than test thread priority
1268  */
try_queue_no_yield(struct k_work_q * wq)1269 static bool try_queue_no_yield(struct k_work_q *wq)
1270 {
1271 	int rc;
1272 	bool is_high = (k_thread_priority_get(k_work_queue_thread_get(wq))
1273 			< k_thread_priority_get(k_current_get()));
1274 
1275 	TC_PRINT("Testing no-yield on %s-priority queue\n",
1276 		 is_high ? "high" : "low");
1277 	reset_counters();
1278 
1279 	/* Submit two work items directly to the cooperative queue. */
1280 
1281 	k_work_init(&common_work, counter_handler);
1282 	k_work_init_delayable(&dwork, counter_handler);
1283 
1284 	rc = k_work_submit_to_queue(wq, &common_work);
1285 	zassert_equal(rc, 1);
1286 	rc = k_work_schedule_for_queue(wq, &dwork, K_NO_WAIT);
1287 	zassert_equal(rc, 1);
1288 
1289 	/* Wait for completion */
1290 	zassert_equal(k_work_is_pending(&common_work), true);
1291 	zassert_equal(k_work_delayable_is_pending(&dwork), true);
1292 	rc = k_sem_take(&sync_sem, K_FOREVER);
1293 	zassert_equal(rc, 0);
1294 
1295 	/* Because there was no yield both should have run, and
1296 	 * another yield won't cause anything to happen.
1297 	 */
1298 	zassert_equal(coop_counter(wq), 2);
1299 	zassert_equal(k_work_is_pending(&common_work), false);
1300 	zassert_equal(k_work_delayable_is_pending(&dwork), false);
1301 
1302 	/* The first give unblocked this thread; we need to consume
1303 	 * the give from the second work task.
1304 	 */
1305 	zassert_equal(k_sem_take(&sync_sem, K_NO_WAIT), 0);
1306 
1307 	zassert_equal(k_sem_take(&sync_sem, K_NO_WAIT), -EBUSY);
1308 
1309 	return is_high;
1310 }
1311 
1312 /* Verify that no-yield policy works */
ZTEST(work_1cpu,test_1cpu_queue_no_yield)1313 ZTEST(work_1cpu, test_1cpu_queue_no_yield)
1314 {
1315 	/* This test needs two slots available in the sem! */
1316 	k_sem_init(&sync_sem, 0, 2);
1317 	zassert_equal(try_queue_no_yield(&coophi_queue), true);
1318 	zassert_equal(try_queue_no_yield(&cooplo_queue), false);
1319 	k_sem_init(&sync_sem, 0, 1);
1320 }
1321 
1322 /* Basic functionality with the system work queue. */
ZTEST(work_1cpu,test_1cpu_system_queue)1323 ZTEST(work_1cpu, test_1cpu_system_queue)
1324 {
1325 	int rc;
1326 
1327 	/* Reset state and use the non-blocking handler */
1328 	reset_counters();
1329 	k_work_init(&common_work, counter_handler);
1330 	zassert_equal(k_work_busy_get(&common_work), 0);
1331 
1332 	/* Submit to the system queue */
1333 	rc = k_work_submit(&common_work);
1334 	zassert_equal(rc, 1);
1335 	zassert_equal(k_work_busy_get(&common_work), K_WORK_QUEUED);
1336 
1337 	/* Shouldn't have been started since test thread is
1338 	 * cooperative.
1339 	 */
1340 	zassert_equal(system_counter(), 0);
1341 
1342 	/* Let it run, then check it didn't finish. */
1343 	k_sleep(K_TICKS(1));
1344 	zassert_equal(system_counter(), 1);
1345 	zassert_equal(k_work_busy_get(&common_work), 0);
1346 
1347 	/* Flush the sync state from completion */
1348 	rc = k_sem_take(&sync_sem, K_NO_WAIT);
1349 	zassert_equal(rc, 0);
1350 }
1351 
ZTEST(work_1cpu,test_1cpu_system_schedule)1352 ZTEST(work_1cpu, test_1cpu_system_schedule)
1353 {
1354 	int rc;
1355 	uint32_t sched_ms;
1356 	uint32_t max_ms = k_ticks_to_ms_ceil32(1U
1357 				+ k_ms_to_ticks_ceil32(DELAY_MS));
1358 	uint32_t elapsed_ms;
1359 
1360 	/* Reset state and use non-blocking handler */
1361 	reset_counters();
1362 	k_work_init_delayable(&dwork, counter_handler);
1363 
1364 	/* Verify that work is idle and marked delayable. */
1365 	zassert_equal(k_work_delayable_busy_get(&dwork), 0);
1366 	zassert_equal(dwork.work.flags & K_WORK_DELAYABLE, K_WORK_DELAYABLE,
1367 		       NULL);
1368 
1369 	/* Align to tick, then schedule after normal delay. */
1370 	k_sleep(K_TICKS(1));
1371 	sched_ms = k_uptime_get_32();
1372 	rc = k_work_schedule(&dwork, K_MSEC(DELAY_MS));
1373 	zassert_equal(rc, 1);
1374 	zassert_equal(k_work_delayable_busy_get(&dwork), K_WORK_DELAYED);
1375 
1376 	/* Scheduling again does nothing. */
1377 	rc = k_work_schedule(&dwork, K_NO_WAIT);
1378 	zassert_equal(rc, 0);
1379 
1380 	/* Wait for completion */
1381 	rc = k_sem_take(&sync_sem, K_FOREVER);
1382 	zassert_equal(rc, 0);
1383 
1384 	/* Make sure it ran and is now idle */
1385 	zassert_equal(system_counter(), 1);
1386 	zassert_equal(k_work_delayable_busy_get(&dwork), 0);
1387 
1388 	/* Check that the delay is within the expected range. */
1389 	elapsed_ms = last_handle_ms - sched_ms;
1390 	zassert_true(elapsed_ms >= DELAY_MS,
1391 		     "short %u < %u\n", elapsed_ms, DELAY_MS);
1392 	zassert_true(elapsed_ms <= max_ms,
1393 		     "long %u > %u\n", elapsed_ms, max_ms);
1394 }
1395 
ZTEST(work_1cpu,test_1cpu_system_reschedule)1396 ZTEST(work_1cpu, test_1cpu_system_reschedule)
1397 {
1398 	int rc;
1399 	uint32_t sched_ms;
1400 	uint32_t max_ms = k_ticks_to_ms_ceil32(1U
1401 				+ k_ms_to_ticks_ceil32(DELAY_MS));
1402 	uint32_t elapsed_ms;
1403 
1404 	/* Reset state and use non-blocking handler */
1405 	reset_counters();
1406 	k_work_init_delayable(&dwork, counter_handler);
1407 
1408 	/* Verify that work is idle and marked delayable. */
1409 	zassert_equal(k_work_delayable_busy_get(&dwork), 0);
1410 	zassert_equal(dwork.work.flags & K_WORK_DELAYABLE, K_WORK_DELAYABLE,
1411 		       NULL);
1412 
1413 	/* Schedule to the preempt queue after twice the standard
1414 	 * delay.
1415 	 */
1416 	rc = k_work_reschedule(&dwork, K_MSEC(2U * DELAY_MS));
1417 	zassert_equal(rc, 1);
1418 	zassert_equal(k_work_delayable_busy_get(&dwork), K_WORK_DELAYED);
1419 
1420 	/* Align to tick then reschedule on the system queue for
1421 	 * the standard delay.
1422 	 */
1423 	k_sleep(K_TICKS(1));
1424 	sched_ms = k_uptime_get_32();
1425 	rc = k_work_reschedule(&dwork, K_MSEC(DELAY_MS));
1426 	zassert_equal(rc, 1);
1427 	zassert_equal(k_work_delayable_busy_get(&dwork), K_WORK_DELAYED);
1428 
1429 	/* Wait for completion */
1430 	rc = k_sem_take(&sync_sem, K_FOREVER);
1431 	zassert_equal(rc, 0);
1432 
1433 	/* Make sure it ran on the system queue and is now idle */
1434 	zassert_equal(system_counter(), 1);
1435 	zassert_equal(k_work_delayable_busy_get(&dwork), 0);
1436 
1437 	/* Check that the delay is within the expected range. */
1438 	elapsed_ms = last_handle_ms - sched_ms;
1439 	zassert_true(elapsed_ms >= DELAY_MS,
1440 		     "short %u < %u\n", elapsed_ms, DELAY_MS);
1441 	zassert_true(elapsed_ms <= max_ms,
1442 		     "long %u > %u\n", elapsed_ms, max_ms);
1443 }
1444 
ZTEST(work,test_nop)1445 ZTEST(work, test_nop)
1446 {
1447 	ztest_test_skip();
1448 }
1449 
workq_setup(void)1450 void *workq_setup(void)
1451 {
1452 	main_thread = k_current_get();
1453 	k_sem_init(&sync_sem, 0, 1);
1454 	k_sem_init(&rel_sem, 0, 1);
1455 
1456 	test_work_init();
1457 	test_delayable_init();
1458 
1459 	if (run_flag) {
1460 		test_queue_start();
1461 		run_flag = false;
1462 	}
1463 
1464 	return NULL;
1465 }
1466 
1467 ZTEST_SUITE(work_1cpu, NULL, workq_setup, ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
1468 ZTEST_SUITE(work, NULL, workq_setup, NULL, NULL, NULL);
1469