Skip to content

Commit 160940b

Browse files
Merge pull request #4682 from bulislaw/sem_tests
Test: RTOS: Semaphore: Rework tests
2 parents 185b723 + 2963308 commit 160940b

File tree

2 files changed

+179
-8
lines changed

2 files changed

+179
-8
lines changed

TESTS/mbedmicro-rtos-mbed/semaphore/main.cpp

Lines changed: 174 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
#include "mbed.h"
22
#include "greentea-client/test_env.h"
3+
#include "unity.h"
4+
#include "utest.h"
35
#include "rtos.h"
46

7+
using namespace utest::v1;
8+
59
#if defined(MBED_RTOS_SINGLE_THREAD)
610
#error [NOT_SUPPORTED] test not supported
711
#endif
812

9-
#define THREAD_DELAY 75
13+
#define THREAD_DELAY 30
1014
#define SEMAPHORE_SLOTS 2
1115
#define SEM_CHANGES 100
16+
#define SHORT_WAIT 5
1217

1318
#define THREAD_STACK_SIZE 512
1419

@@ -18,7 +23,8 @@ volatile int change_counter = 0;
1823
volatile int sem_counter = 0;
1924
volatile bool sem_defect = false;
2025

21-
void test_thread(int const *delay) {
26+
void test_thread(int const *delay)
27+
{
2228
const int thread_delay = *delay;
2329
while (true) {
2430
two_slots.wait();
@@ -34,9 +40,14 @@ void test_thread(int const *delay) {
3440
}
3541
}
3642

37-
int main (void) {
38-
GREENTEA_SETUP(20, "default_auto");
43+
/* Test multiple threads
3944
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+
{
4051
const int t1_delay = THREAD_DELAY * 1;
4152
const int t2_delay = THREAD_DELAY * 2;
4253
const int t3_delay = THREAD_DELAY * 3;
@@ -57,7 +68,164 @@ int main (void) {
5768
break;
5869
}
5970
}
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);
60227

61-
GREENTEA_TESTSUITE_RESULT(!sem_defect);
62-
return 0;
228+
int main()
229+
{
230+
return !Harness::run(specification);
63231
}

rtos/Semaphore.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@ class Semaphore : private mbed::NonCopyable<Semaphore> {
5353

5454
/** Wait until a Semaphore resource becomes available.
5555
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
56-
@return number of available tokens, or -1 in case of incorrect parameters
56+
@return number of available tokens, before taking one; or -1 in case of incorrect parameters
5757
*/
5858
int32_t wait(uint32_t millisec=osWaitForever);
5959

6060
/** Release a Semaphore resource that was obtain with Semaphore::wait.
61-
@return status code that indicates the execution status of the function.
61+
@return status code that indicates the execution status of the function:
62+
@a osOK the token has been correctly released.
63+
@a osErrorResource the maximum token count has been reached.
64+
@a osErrorParameter internal error.
6265
*/
6366
osStatus release(void);
6467

0 commit comments

Comments
 (0)