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