blob: 10a94d1c560c6a505740dfa756bbb6afbab12b3a [file] [log] [blame]
Jerome Forissiercb163872025-04-18 16:09:38 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2025 Linaro Limited
4 *
5 * Unit test for uthread
6 */
7
8#include <stdbool.h>
9#include <test/lib.h>
10#include <test/ut.h>
11#include <uthread.h>
12
13static int count;
14
15/* A thread entry point */
16static void worker(void *arg)
17{
18 int loops = (int)(unsigned long)arg;
19 int i;
20
21 for (i = 0; i < loops; i++) {
22 count++;
23 uthread_schedule();
24 }
25}
26
27/*
28 * uthread() - testing the uthread API
29 *
30 * This function creates two threads with the same entry point. The first one
31 * receives 5 as an argument, the second one receives 10. The number indicates
32 * the number of time the worker thread should loop on uthread_schedule()
33 * before returning. The workers increment a global counter each time they loop.
34 * As a result the main thread knows how many times it should call
35 * uthread_schedule() to let the two threads proceed, and it also knows which
36 * value the counter should have at any moment.
37 */
38static int uthread(struct unit_test_state *uts)
39{
40 int i;
41 int id1, id2;
42
43 count = 0;
44 id1 = uthread_grp_new_id();
45 ut_assert(id1 != 0);
46 id2 = uthread_grp_new_id();
47 ut_assert(id2 != 0);
48 ut_assert(id1 != id2);
49 ut_assertok(uthread_create(NULL, worker, (void *)5, 0, id1));
50 ut_assertok(uthread_create(NULL, worker, (void *)10, 0, 0));
51 /*
52 * The first call is expected to schedule the first worker, which will
53 * schedule the second one, which will schedule back to the main thread
54 * (here). Therefore count should be 2.
55 */
56 ut_assert(uthread_schedule());
57 ut_asserteq(2, count);
58 ut_assert(!uthread_grp_done(id1));
59 /* Four more calls should bring the count to 10 */
60 for (i = 0; i < 4; i++) {
61 ut_assert(!uthread_grp_done(id1));
62 ut_assert(uthread_schedule());
63 }
64 ut_asserteq(10, count);
65 /* This one allows the first worker to exit */
66 ut_assert(uthread_schedule());
67 /* At this point there should be no runnable thread in group 'id1' */
68 ut_assert(uthread_grp_done(id1));
69 /* Five more calls for the second worker to finish incrementing */
70 for (i = 0; i < 5; i++)
71 ut_assert(uthread_schedule());
72 ut_asserteq(15, count);
73 /* Plus one call to let the second worker return from its entry point */
74 ut_assert(uthread_schedule());
75 /* Now both tasks should be done, schedule should return false */
76 ut_assert(!uthread_schedule());
77
78 return 0;
79}
80LIB_TEST(uthread, 0);
Jerome Forissier23b3a6b2025-04-18 16:09:39 +020081
82struct mw_args {
83 struct unit_test_state *uts;
84 struct uthread_mutex *m;
85 int flag;
86};
87
88static int mutex_worker_ret;
89
90static int _mutex_worker(struct mw_args *args)
91{
92 struct unit_test_state *uts = args->uts;
93
94 ut_asserteq(-EBUSY, uthread_mutex_trylock(args->m));
95 ut_assertok(uthread_mutex_lock(args->m));
96 args->flag = 1;
97 ut_assertok(uthread_mutex_unlock(args->m));
98
99 return 0;
100}
101
102static void mutex_worker(void *arg)
103{
104 mutex_worker_ret = _mutex_worker((struct mw_args *)arg);
105}
106
107/*
108 * thread_mutex() - testing uthread mutex operations
109 *
110 */
111static int uthread_mutex(struct unit_test_state *uts)
112{
113 struct uthread_mutex m = UTHREAD_MUTEX_INITIALIZER;
114 struct mw_args args = { .uts = uts, .m = &m, .flag = 0 };
115 int id;
116 int i;
117
118 id = uthread_grp_new_id();
119 ut_assert(id != 0);
120 /* Take the mutex */
121 ut_assertok(uthread_mutex_lock(&m));
122 /* Start a thread */
123 ut_assertok(uthread_create(NULL, mutex_worker, (void *)&args, 0,
124 id));
125 /* Let the thread run for a bit */
126 for (i = 0; i < 100; i++)
127 ut_assert(uthread_schedule());
128 /* Thread should not have set the flag due to the mutex */
129 ut_asserteq(0, args.flag);
130 /* Release the mutex */
131 ut_assertok(uthread_mutex_unlock(&m));
132 /* Schedule the thread until it is done */
133 while (uthread_schedule())
134 ;
135 /* Now the flag should be set */
136 ut_asserteq(1, args.flag);
137 /* And the mutex should be available */
138 ut_assertok(uthread_mutex_trylock(&m));
139 ut_assertok(uthread_mutex_unlock(&m));
140
141 /* Of course no error are expected from the thread routine */
142 ut_assertok(mutex_worker_ret);
143
144 return 0;
145}
146LIB_TEST(uthread_mutex, 0);