1
1
#include " mbed.h"
2
2
#include " greentea-client/test_env.h"
3
+ #include " unity.h"
4
+ #include " utest.h"
3
5
#include " rtos.h"
4
6
7
+ using namespace utest ::v1;
8
+
5
9
#if defined(MBED_RTOS_SINGLE_THREAD)
6
10
#error [NOT_SUPPORTED] test not supported
7
11
#endif
8
12
9
- #define THREAD_DELAY 75
13
+ #define THREAD_DELAY 30
10
14
#define SEMAPHORE_SLOTS 2
11
15
#define SEM_CHANGES 100
16
+ #define SHORT_WAIT 5
12
17
13
18
#define THREAD_STACK_SIZE 512
14
19
@@ -18,7 +23,8 @@ volatile int change_counter = 0;
18
23
volatile int sem_counter = 0 ;
19
24
volatile bool sem_defect = false ;
20
25
21
- void test_thread (int const *delay) {
26
+ void test_thread (int const *delay)
27
+ {
22
28
const int thread_delay = *delay;
23
29
while (true ) {
24
30
two_slots.wait ();
@@ -34,9 +40,14 @@ void test_thread(int const *delay) {
34
40
}
35
41
}
36
42
37
- int main (void ) {
38
- GREENTEA_SETUP (20 , " default_auto" );
43
+ /* Test multiple threads
39
44
45
+ Given 3 threads started with different delays and a semaphore with 2 tokens
46
+ when each thread runs it tries to acquire a token
47
+ then no more than two threads should be able to access protected region
48
+ */
49
+ void test_multi ()
50
+ {
40
51
const int t1_delay = THREAD_DELAY * 1 ;
41
52
const int t2_delay = THREAD_DELAY * 2 ;
42
53
const int t3_delay = THREAD_DELAY * 3 ;
@@ -57,7 +68,164 @@ int main (void) {
57
68
break ;
58
69
}
59
70
}
71
+ }
72
+
73
+ struct thread_data {
74
+ Semaphore *sem;
75
+ uint32_t data;
76
+ };
77
+
78
+ void single_thread (struct thread_data *data)
79
+ {
80
+ int32_t cnt = data->sem ->wait ();
81
+ TEST_ASSERT_EQUAL (1 , cnt);
82
+ data->data ++;
83
+ }
84
+
85
+ /* * Test single thread
86
+
87
+ Given a two threads A & B and a semaphore (with count of 0) and a counter (equals to 0)
88
+ when thread B calls @a wait
89
+ then thread B waits for a token to become available
90
+ then the counter is equal to 0
91
+ when thread A calls @a release on the semaphore
92
+ then thread B acquires a token and increments the counter
93
+ then the counter equals to 1
94
+ */
95
+ void test_single_thread ()
96
+ {
97
+ Thread t (osPriorityNormal, THREAD_STACK_SIZE);
98
+ Semaphore sem (0 );
99
+ struct thread_data data;
100
+ osStatus res;
101
+
102
+ data.sem = &sem;
103
+ data.data = 0 ;
104
+
105
+ res = t.start (callback (single_thread, &data));
106
+ TEST_ASSERT_EQUAL (osOK, res);
107
+ Thread::wait (SHORT_WAIT);
108
+
109
+ TEST_ASSERT_EQUAL (Thread::WaitingSemaphore, t.get_state ());
110
+ TEST_ASSERT_EQUAL (0 , data.data );
111
+
112
+ res = sem.release ();
113
+ TEST_ASSERT_EQUAL (osOK, res);
114
+
115
+ Thread::wait (SHORT_WAIT);
116
+
117
+ TEST_ASSERT_EQUAL (1 , data.data );
118
+
119
+ t.join ();
120
+ }
121
+
122
+ void timeout_thread (Semaphore *sem)
123
+ {
124
+ int32_t cnt = sem->wait (30 );
125
+ TEST_ASSERT_EQUAL (0 , cnt);
126
+ }
127
+
128
+ /* * Test timeout
129
+
130
+ Given thread and a semaphore with no tokens available
131
+ when thread calls @a wait on the semaphore with timeout of 10ms
132
+ then the thread waits for 10ms and timeouts after
133
+ */
134
+ void test_timeout ()
135
+ {
136
+ Thread t (osPriorityNormal, THREAD_STACK_SIZE);
137
+ Semaphore sem (0 );
138
+ osStatus res;
139
+
140
+ uint32_t start = us_ticker_read ();
141
+ res = t.start (callback (timeout_thread, &sem));
142
+ TEST_ASSERT_EQUAL (osOK, res);
143
+ Thread::wait (SHORT_WAIT);
144
+
145
+ TEST_ASSERT_EQUAL (Thread::WaitingSemaphore, t.get_state ());
146
+
147
+ t.join ();
148
+ TEST_ASSERT_UINT32_WITHIN (5000 , 30000 , us_ticker_read () - start);
149
+ }
150
+
151
+ /* * Test no timeouts
152
+
153
+ Test 1 token no timeout
154
+ Given thread and a semaphore with one token available
155
+ when thread calls @a wait on the semaphore with timeout of 0ms
156
+ then the thread acquires the token immediately
157
+
158
+ Test 0 tokens no timeout
159
+ Given thread and a semaphore with no tokens available
160
+ when thread calls @a wait on the semaphore with timeout of 0ms
161
+ then the thread returns immediately without acquiring a token
162
+ */
163
+ template <int T>
164
+ void test_no_timeout ()
165
+ {
166
+ Semaphore sem (T);
167
+
168
+ uint32_t start = us_ticker_read ();
169
+
170
+ int32_t cnt = sem.wait (0 );
171
+ TEST_ASSERT_EQUAL (T, cnt);
172
+
173
+ TEST_ASSERT_UINT32_WITHIN (5000 , 0 , us_ticker_read () - start);
174
+ }
175
+
176
+ /* * Test multiple tokens wait
177
+
178
+ Given a thread and a semaphore initialized with 5 tokens
179
+ when thread calls @a wait 6 times on the semaphore
180
+ then the token counts goes to zero
181
+ */
182
+ void test_multiple_tokens_wait ()
183
+ {
184
+ Semaphore sem (5 );
185
+
186
+ for (int i = 5 ; i >= 0 ; i--) {
187
+ int32_t cnt = sem.wait (0 );
188
+ TEST_ASSERT_EQUAL (i, cnt);
189
+ }
190
+ }
191
+
192
+ /* * Test multiple tokens release
193
+
194
+ Given a thread and a semaphore initialized with zero tokens and max of 5
195
+ when thread calls @a release 6 times on the semaphore
196
+ then the token count should be equal to 5 and last release call should fail
197
+ */
198
+ void test_multiple_tokens_release ()
199
+ {
200
+ Semaphore sem (0 , 5 );
201
+
202
+ for (int i = 5 ; i > 0 ; i--) {
203
+ osStatus stat = sem.release ();
204
+ TEST_ASSERT_EQUAL (osOK, stat);
205
+ }
206
+ osStatus stat = sem.release ();
207
+ TEST_ASSERT_EQUAL (osErrorResource, stat);
208
+ }
209
+
210
+ utest::v1::status_t test_setup (const size_t number_of_cases)
211
+ {
212
+ GREENTEA_SETUP (10 , " default_auto" );
213
+ return verbose_test_setup_handler (number_of_cases);
214
+ }
215
+
216
+ Case cases[] = {
217
+ Case (" Test single thread" , test_single_thread),
218
+ Case (" Test timeout" , test_timeout),
219
+ Case (" Test 1 token no timeout" , test_no_timeout<1 >),
220
+ Case (" Test 0 tokens no timeout" , test_no_timeout<0 >),
221
+ Case (" Test multiple tokens wait" , test_multiple_tokens_wait),
222
+ Case (" Test multiple tokens release" , test_multiple_tokens_release),
223
+ Case (" Test multiple threads" , test_multi)
224
+ };
225
+
226
+ Specification specification (test_setup, cases);
60
227
61
- GREENTEA_TESTSUITE_RESULT (!sem_defect);
62
- return 0 ;
228
+ int main ()
229
+ {
230
+ return !Harness::run (specification);
63
231
}
0 commit comments