Skip to content

Commit c2fdc0d

Browse files
authored
Merge pull request #7423 from mprse/mutex_lock_assert
Fix issue #6872 - Mutex lock has possibility to fail at runtime (returning status flag)
2 parents 44925d8 + fba9c4b commit c2fdc0d

File tree

4 files changed

+113
-69
lines changed

4 files changed

+113
-69
lines changed

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

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ volatile bool mutex_defect = false;
4848
bool manipulate_protected_zone(const int thread_delay)
4949
{
5050
bool result = true;
51+
osStatus stat;
5152

52-
osStatus stat = stdio_mutex.lock();
53-
TEST_ASSERT_EQUAL(osOK, stat);
53+
stdio_mutex.lock();
5454

5555
core_util_critical_section_enter();
5656
if (changing_counter == true) {
@@ -68,8 +68,8 @@ bool manipulate_protected_zone(const int thread_delay)
6868
changing_counter = false;
6969
core_util_critical_section_exit();
7070

71-
stat = stdio_mutex.unlock();
72-
TEST_ASSERT_EQUAL(osOK, stat);
71+
stdio_mutex.unlock();
72+
7373
return result;
7474
}
7575

@@ -118,20 +118,18 @@ void test_multiple_threads(void)
118118

119119
void test_dual_thread_nolock_lock_thread(Mutex *mutex)
120120
{
121-
osStatus stat = mutex->lock(osWaitForever);
122-
TEST_ASSERT_EQUAL(osOK, stat);
121+
osStatus stat;
122+
mutex->lock();
123123

124-
stat = mutex->unlock();
125-
TEST_ASSERT_EQUAL(osOK, stat);
124+
mutex->unlock();
126125
}
127126

128127
void test_dual_thread_nolock_trylock_thread(Mutex *mutex)
129128
{
130129
bool stat_b = mutex->trylock();
131130
TEST_ASSERT_EQUAL(true, stat_b);
132131

133-
osStatus stat = mutex->unlock();
134-
TEST_ASSERT_EQUAL(osOK, stat);
132+
mutex->unlock();
135133
}
136134

137135
/** Test dual thread no-lock
@@ -140,13 +138,13 @@ void test_dual_thread_nolock_trylock_thread(Mutex *mutex)
140138
Given two threads A & B and a mutex
141139
When thread A creates a mutex and starts thread B
142140
and thread B calls @a lock and @a unlock
143-
Then returned statuses are osOK
141+
Then @a lock and @a unlock operations are successfully performed.
144142
145143
Test dual thread second thread trylock
146144
Given two threads A & B and a mutex
147145
When thread A creates a mutex and starts thread B
148146
and thread B calls @a trylock and @a unlock
149-
Then returned statuses are true and osOK
147+
Then @a trylock and @a unlock operations are successfully performed.
150148
*/
151149
template <void (*F)(Mutex *)>
152150
void test_dual_thread_nolock(void)
@@ -161,8 +159,7 @@ void test_dual_thread_nolock(void)
161159

162160
void test_dual_thread_lock_unlock_thread(Mutex *mutex)
163161
{
164-
osStatus stat = mutex->lock(osWaitForever);
165-
TEST_ASSERT_EQUAL(osOK, stat);
162+
mutex->lock();
166163
}
167164

168165
/** Test dual thread lock unlock
@@ -180,13 +177,11 @@ void test_dual_thread_lock_unlock(void)
180177
osStatus stat;
181178
Thread thread(osPriorityNormal, TEST_STACK_SIZE);
182179

183-
stat = mutex.lock();
184-
TEST_ASSERT_EQUAL(osOK, stat);
180+
mutex.lock();
185181

186182
thread.start(callback(test_dual_thread_lock_unlock_thread, &mutex));
187183

188-
stat = mutex.unlock();
189-
TEST_ASSERT_EQUAL(osOK, stat);
184+
mutex.unlock();
190185

191186
wait_ms(TEST_DELAY);
192187
}
@@ -202,9 +197,9 @@ void test_dual_thread_lock_lock_thread(Mutex *mutex)
202197
Timer timer;
203198
timer.start();
204199

205-
osStatus stat = mutex->lock(TEST_DELAY);
206-
TEST_ASSERT_EQUAL(osErrorTimeout, stat);
207-
TEST_ASSERT_UINT32_WITHIN(5000, TEST_DELAY * 1000, timer.read_us());
200+
bool stat = mutex->trylock_for(TEST_DELAY);
201+
TEST_ASSERT_EQUAL(false, stat);
202+
TEST_ASSERT_UINT32_WITHIN(5000, TEST_DELAY*1000, timer.read_us());
208203
}
209204

210205
/** Test dual thread lock
@@ -228,46 +223,40 @@ void test_dual_thread_lock(void)
228223
osStatus stat;
229224
Thread thread(osPriorityNormal, TEST_STACK_SIZE);
230225

231-
stat = mutex.lock();
232-
TEST_ASSERT_EQUAL(osOK, stat);
226+
mutex.lock();
233227

234228
thread.start(callback(F, &mutex));
235229

236230
wait_ms(TEST_LONG_DELAY);
237231

238-
stat = mutex.unlock();
239-
TEST_ASSERT_EQUAL(osOK, stat);
232+
mutex.unlock();
240233
}
241234

242235
/** Test single thread lock recursive
243236
244237
Given a mutex and a single running thread
245238
When thread calls @a lock twice and @a unlock twice on the mutex
246-
Then the returned statuses are osOK
239+
Then @a lock and @a unlock operations are successfully performed.
247240
*/
248241
void test_single_thread_lock_recursive(void)
249242
{
250243
Mutex mutex;
251244
osStatus stat;
252245

253-
stat = mutex.lock();
254-
TEST_ASSERT_EQUAL(osOK, stat);
246+
mutex.lock();
255247

256-
stat = mutex.lock();
257-
TEST_ASSERT_EQUAL(osOK, stat);
248+
mutex.lock();
258249

259-
stat = mutex.unlock();
260-
TEST_ASSERT_EQUAL(osOK, stat);
250+
mutex.unlock();
261251

262-
stat = mutex.unlock();
263-
TEST_ASSERT_EQUAL(osOK, stat);
252+
mutex.unlock();
264253
}
265254

266255
/** Test single thread trylock
267256
268257
Given a mutex and a single running thread
269258
When thread calls @a trylock and @a unlock on the mutex
270-
Then the returned statuses are osOK
259+
Then @a trylock and @a unlock operations are successfully performed.
271260
*/
272261
void test_single_thread_trylock(void)
273262
{
@@ -276,26 +265,23 @@ void test_single_thread_trylock(void)
276265
bool stat_b = mutex.trylock();
277266
TEST_ASSERT_EQUAL(true, stat_b);
278267

279-
osStatus stat = mutex.unlock();
280-
TEST_ASSERT_EQUAL(osOK, stat);
268+
mutex.unlock();
281269
}
282270

283271
/** Test single thread lock
284272
285273
Given a mutex and a single running thread
286274
When thread calls @a lock and @a unlock on the mutex
287-
Then the returned statuses are osOK
275+
Then @a lock and @a unlock operations are successfully performed.
288276
*/
289277
void test_single_thread_lock(void)
290278
{
291279
Mutex mutex;
292280
osStatus stat;
293281

294-
stat = mutex.lock();
295-
TEST_ASSERT_EQUAL(osOK, stat);
282+
mutex.lock();
296283

297-
stat = mutex.unlock();
298-
TEST_ASSERT_EQUAL(osOK, stat);
284+
mutex.unlock();
299285
}
300286

301287
utest::v1::status_t test_setup(const size_t number_of_cases)

features/lorawan/lorastack/mac/LoRaMac.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -411,15 +411,11 @@ class LoRaMac {
411411
#if MBED_CONF_RTOS_PRESENT
412412
void lock(void)
413413
{
414-
osStatus status = _mutex.lock();
415-
MBED_ASSERT(status == osOK);
416-
(void) status;
414+
_mutex.lock();
417415
}
418416
void unlock(void)
419417
{
420-
osStatus status = _mutex.unlock();
421-
MBED_ASSERT(status == osOK);
422-
(void) status;
418+
_mutex.unlock();
423419
}
424420
#else
425421
void lock(void) { }

rtos/Mutex.cpp

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ Mutex::Mutex(const char *name)
4141
void Mutex::constructor(const char *name)
4242
{
4343
memset(&_obj_mem, 0, sizeof(_obj_mem));
44-
osMutexAttr_t attr = { 0 };
44+
osMutexAttr_t attr =
45+
{ 0 };
4546
attr.name = name ? name : "aplication_unnamed_mutex";
4647
attr.cb_mem = &_obj_mem;
4748
attr.cb_size = sizeof(_obj_mem);
@@ -50,30 +51,63 @@ void Mutex::constructor(const char *name)
5051
MBED_ASSERT(_id);
5152
}
5253

53-
osStatus Mutex::lock(uint32_t millisec) {
54+
osStatus Mutex::lock(void)
55+
{
56+
osStatus status = osMutexAcquire(_id, osWaitForever);
57+
if (osOK == status) {
58+
_count++;
59+
}
60+
61+
if (status != osOK) {
62+
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status);
63+
}
64+
65+
return osOK;
66+
}
67+
68+
osStatus Mutex::lock(uint32_t millisec)
69+
{
5470
osStatus status = osMutexAcquire(_id, millisec);
5571
if (osOK == status) {
5672
_count++;
5773
}
74+
75+
bool success = (status == osOK ||
76+
(status == osErrorResource && millisec == 0) ||
77+
(status == osErrorTimeout && millisec != osWaitForever));
78+
79+
if (!success) {
80+
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status);
81+
}
82+
5883
return status;
5984
}
6085

61-
bool Mutex::trylock() {
86+
bool Mutex::trylock()
87+
{
6288
return trylock_for(0);
6389
}
6490

65-
bool Mutex::trylock_for(uint32_t millisec) {
66-
osStatus status = lock(millisec);
91+
bool Mutex::trylock_for(uint32_t millisec)
92+
{
93+
osStatus status = osMutexAcquire(_id, millisec);
6794
if (status == osOK) {
6895
return true;
6996
}
7097

71-
MBED_ASSERT(status == osErrorTimeout || status == osErrorResource);
98+
bool success = (status == osOK ||
99+
(status == osErrorResource && millisec == 0) ||
100+
(status == osErrorTimeout && millisec != osWaitForever));
101+
102+
if (!success) {
103+
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status);
104+
}
72105

73106
return false;
74107
}
75108

76-
bool Mutex::trylock_until(uint64_t millisec) {
109+
bool Mutex::trylock_until(uint64_t millisec)
110+
{
77111
uint64_t now = Kernel::get_ms_count();
78112

79113
if (now >= millisec) {
@@ -86,16 +120,26 @@ bool Mutex::trylock_until(uint64_t millisec) {
86120
}
87121
}
88122

89-
osStatus Mutex::unlock() {
123+
osStatus Mutex::unlock()
124+
{
90125
_count--;
91-
return osMutexRelease(_id);
126+
127+
osStatus status = osMutexRelease(_id);
128+
129+
if (status != osOK) {
130+
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_UNLOCK_FAILED), "Mutex unlock failed", status);
131+
}
132+
133+
return osOK;
92134
}
93135

94-
osThreadId Mutex::get_owner() {
136+
osThreadId Mutex::get_owner()
137+
{
95138
return osMutexGetOwner(_id);
96139
}
97140

98-
Mutex::~Mutex() {
141+
Mutex::~Mutex()
142+
{
99143
osMutexDelete(_id);
100144
}
101145

rtos/Mutex.h

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include "platform/NonCopyable.h"
3131
#include "platform/ScopedLock.h"
32+
#include "platform/mbed_toolchain.h"
3233

3334
namespace rtos {
3435
/** \addtogroup rtos */
@@ -73,23 +74,39 @@ class Mutex : private mbed::NonCopyable<Mutex> {
7374
/** Create and Initialize a Mutex object
7475
7576
@param name name to be used for this mutex. It has to stay allocated for the lifetime of the thread.
76-
7777
@note You cannot call this function from ISR context.
7878
*/
7979
Mutex(const char *name);
8080

81-
/** Wait until a Mutex becomes available.
82-
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever)
81+
/**
82+
Wait until a Mutex becomes available.
83+
84+
@return status code that indicates the execution status of the function:
85+
@a osOK the mutex has been obtained.
86+
87+
@note You cannot call this function from ISR context.
88+
@note This function treats RTOS errors as fatal system errors, so can only return osOK.
89+
Use of the return value is deprecated, as the return is expected to become void in the future.
90+
*/
91+
osStatus lock(void);
92+
93+
/**
94+
For backwards compatibility.
95+
@deprecated Do not use this function. This function has been replaced with lock(), trylock() and trylock_for() functions.
96+
97+
Wait until a Mutex becomes available.
98+
@param millisec timeout value or 0 in case of no time-out.
8399
@return status code that indicates the execution status of the function:
84100
@a osOK the mutex has been obtained.
85101
@a osErrorTimeout the mutex could not be obtained in the given time.
86-
@a osErrorParameter internal error.
87102
@a osErrorResource the mutex could not be obtained when no timeout was specified.
88-
@a osErrorISR this function cannot be called from the interrupt service routine.
89103
90104
@note You cannot call this function from ISR context.
105+
@note This function treats RTOS errors as fatal system errors, so can only return osOK or
106+
osErrorResource in case when millisec is 0 or osErrorTimeout if millisec is not osWaitForever.
91107
*/
92-
osStatus lock(uint32_t millisec=osWaitForever);
108+
MBED_DEPRECATED_SINCE("mbed-os-5.10.0", "Replaced with lock(), trylock() and trylock_for() functions")
109+
osStatus lock(uint32_t millisec);
93110

94111
/** Try to lock the mutex, and return immediately
95112
@return true if the mutex was acquired, false otherwise.
@@ -123,14 +140,15 @@ class Mutex : private mbed::NonCopyable<Mutex> {
123140
*/
124141
bool trylock_until(uint64_t millisec);
125142

126-
/** Unlock the mutex that has previously been locked by the same thread
143+
/**
144+
Unlock the mutex that has previously been locked by the same thread
145+
127146
@return status code that indicates the execution status of the function:
128147
@a osOK the mutex has been released.
129-
@a osErrorParameter internal error.
130-
@a osErrorResource the mutex was not locked or the current thread wasn't the owner.
131-
@a osErrorISR this function cannot be called from the interrupt service routine.
132148
133149
@note You cannot call this function from ISR context.
150+
@note This function treats RTOS errors as fatal system errors, so can only return osOK.
151+
Use of the return value is deprecated, as the return is expected to become void in the future.
134152
*/
135153
osStatus unlock();
136154

0 commit comments

Comments
 (0)