fork

Revision:
119:19af2d39a542
Parent:
118:6635230e06ba
Child:
123:58563e6cba1e
--- a/rtos/Thread.cpp	Mon Jul 25 14:12:24 2016 +0100
+++ b/rtos/Thread.cpp	Wed Aug 10 16:09:20 2016 +0100
@@ -63,16 +63,21 @@
 }
 
 osStatus Thread::start(Callback<void()> task) {
+    _mutex.lock();
+
     if (_tid != 0) {
+        _mutex.unlock();
         return osErrorParameter;
     }
 
 #if defined(__MBED_CMSIS_RTOS_CA9) || defined(__MBED_CMSIS_RTOS_CM)
-    _thread_def.pthread = (void (*)(const void *))Callback<void()>::thunk;
+    _thread_def.pthread = Thread::_thunk;
     if (_thread_def.stack_pointer == NULL) {
         _thread_def.stack_pointer = new uint32_t[_thread_def.stacksize/sizeof(uint32_t)];
-        if (_thread_def.stack_pointer == NULL)
+        if (_thread_def.stack_pointer == NULL) {
+            _mutex.unlock();
             return osErrorNoMemory;
+        }
     }
 
     //Fill the stack with a magic word for maximum usage checking
@@ -81,67 +86,122 @@
     }
 #endif
     _task = task;
-    _tid = osThreadCreate(&_thread_def, &_task);
+    _tid = osThreadCreate(&_thread_def, this);
     if (_tid == NULL) {
         if (_dynamic_stack) delete[] (_thread_def.stack_pointer);
+        _mutex.unlock();
         return osErrorResource;
     }
+
+    _mutex.unlock();
     return osOK;
 }
 
 osStatus Thread::terminate() {
-    return osThreadTerminate(_tid);
+    osStatus ret;
+    _mutex.lock();
+
+    ret = osThreadTerminate(_tid);
+    _tid = (osThreadId)NULL;
+
+    // Wake threads joining the terminated thread
+    _join_sem.release();
+
+    _mutex.unlock();
+    return ret;
 }
 
 osStatus Thread::join() {
-    while (true) {
-        uint8_t state = get_state();
-        if (state == Thread::Inactive || state == osErrorParameter) {
-            return osOK;
-        }
-
-        osStatus status = yield();
-        if (status != osOK) {
-            return status;
-        }
+    int32_t ret = _join_sem.wait();
+    if (ret < 0) {
+        return osErrorOS;
     }
+    // Release sem so any other threads joining this thread wake up
+    _join_sem.release();
+    return osOK;
 }
 
 osStatus Thread::set_priority(osPriority priority) {
-    return osThreadSetPriority(_tid, priority);
+    osStatus ret;
+    _mutex.lock();
+
+    ret = osThreadSetPriority(_tid, priority);
+
+    _mutex.unlock();
+    return ret;
 }
 
 osPriority Thread::get_priority() {
-    return osThreadGetPriority(_tid);
+    osPriority ret;
+    _mutex.lock();
+
+    ret = osThreadGetPriority(_tid);
+
+    _mutex.unlock();
+    return ret;
 }
 
 int32_t Thread::signal_set(int32_t signals) {
+    // osSignalSet is thread safe as long as the underlying
+    // thread does not get terminated or return from main
     return osSignalSet(_tid, signals);
 }
 
 int32_t Thread::signal_clr(int32_t signals) {
+    // osSignalClear is thread safe as long as the underlying
+    // thread does not get terminated or return from main
     return osSignalClear(_tid, signals);
 }
 
 Thread::State Thread::get_state() {
 #if !defined(__MBED_CMSIS_RTOS_CA9) && !defined(__MBED_CMSIS_RTOS_CM)
 #ifdef CMSIS_OS_RTX
-    return ((State)_thread_def.tcb.state);
+    State status = Deleted;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        status = (State)_thread_def.tcb.state;
+    }
+
+    _mutex.unlock();
+    return status;
 #endif
 #else
-    uint8_t status;
-    status = osThreadGetState(_tid);
-    return ((State)status);
+    State status = Deleted;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        status = (State)osThreadGetState(_tid);
+    }
+
+    _mutex.unlock();
+    return status;
 #endif
 }
 
 uint32_t Thread::stack_size() {
 #ifndef __MBED_CMSIS_RTOS_CA9
 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
-    return _thread_def.tcb.priv_stack;
+    uint32_t size = 0;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        size = _thread_def.tcb.priv_stack;
+    }
+
+    _mutex.unlock();
+    return size;
 #else
-    P_TCB tcb = rt_tid2ptcb(_tid);
-    return tcb->priv_stack;
+    uint32_t size = 0;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        P_TCB tcb = rt_tid2ptcb(_tid);
+        size = tcb->priv_stack;
+    }
+
+    _mutex.unlock();
+    return size;
 #endif
 #else
     return 0;
@@ -151,12 +211,28 @@
 uint32_t Thread::free_stack() {
 #ifndef __MBED_CMSIS_RTOS_CA9
 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
-    uint32_t bottom = (uint32_t)_thread_def.tcb.stack;
-    return _thread_def.tcb.tsk_stack - bottom;
+    uint32_t size = 0;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        uint32_t bottom = (uint32_t)_thread_def.tcb.stack;
+        size = _thread_def.tcb.tsk_stack - bottom;
+    }
+
+    _mutex.unlock();
+    return size;
 #else
-    P_TCB tcb = rt_tid2ptcb(_tid);
-    uint32_t bottom = (uint32_t)tcb->stack;
-    return tcb->tsk_stack - bottom;
+    uint32_t size = 0;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        P_TCB tcb = rt_tid2ptcb(_tid);
+        uint32_t bottom = (uint32_t)tcb->stack;
+        size = tcb->tsk_stack - bottom;
+    }
+
+    _mutex.unlock();
+    return size;
 #endif
 #else
     return 0;
@@ -166,12 +242,28 @@
 uint32_t Thread::used_stack() {
 #ifndef __MBED_CMSIS_RTOS_CA9
 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
-    uint32_t top = (uint32_t)_thread_def.tcb.stack + _thread_def.tcb.priv_stack;
-    return top - _thread_def.tcb.tsk_stack;
+    uint32_t size = 0;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        uint32_t top = (uint32_t)_thread_def.tcb.stack + _thread_def.tcb.priv_stack;
+        size = top - _thread_def.tcb.tsk_stack;
+    }
+
+    _mutex.unlock();
+    return size;
 #else
-    P_TCB tcb = rt_tid2ptcb(_tid);
-    uint32_t top = (uint32_t)tcb->stack + tcb->priv_stack;
-    return top - tcb->tsk_stack;
+    uint32_t size = 0;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        P_TCB tcb = rt_tid2ptcb(_tid);
+        uint32_t top = (uint32_t)tcb->stack + tcb->priv_stack;
+        size =  top - tcb->tsk_stack;
+    }
+
+    _mutex.unlock();
+    return size;
 #endif
 #else
     return 0;
@@ -181,16 +273,32 @@
 uint32_t Thread::max_stack() {
 #ifndef __MBED_CMSIS_RTOS_CA9
 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
-    uint32_t high_mark = 0;
-    while (_thread_def.tcb.stack[high_mark] == 0xE25A2EA5)
-        high_mark++;
-    return _thread_def.tcb.priv_stack - (high_mark * 4);
+    uint32_t size = 0;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        uint32_t high_mark = 0;
+        while (_thread_def.tcb.stack[high_mark] == 0xE25A2EA5)
+            high_mark++;
+        size = _thread_def.tcb.priv_stack - (high_mark * 4);
+    }
+
+    _mutex.unlock();
+    return size;
 #else
-    P_TCB tcb = rt_tid2ptcb(_tid);
-    uint32_t high_mark = 0;
-    while (tcb->stack[high_mark] == 0xE25A2EA5)
-        high_mark++;
-    return tcb->priv_stack - (high_mark * 4);
+    uint32_t size = 0;
+    _mutex.lock();
+
+    if (_tid != NULL) {
+        P_TCB tcb = rt_tid2ptcb(_tid);
+        uint32_t high_mark = 0;
+        while (tcb->stack[high_mark] == 0xE25A2EA5)
+            high_mark++;
+        size = tcb->priv_stack - (high_mark * 4);
+    }
+
+    _mutex.unlock();
+    return size;
 #endif
 #else
     return 0;
@@ -218,6 +326,7 @@
 }
 
 Thread::~Thread() {
+    // terminate is thread safe
     terminate();
 #ifdef __MBED_CMSIS_RTOS_CM
     if (_dynamic_stack) {
@@ -226,4 +335,14 @@
 #endif
 }
 
+void Thread::_thunk(const void * thread_ptr)
+{
+    Thread *t = (Thread*)thread_ptr;
+    t->_task();
+    t->_mutex.lock();
+    t->_tid = (osThreadId)NULL;
+    t->_join_sem.release();
+    // rtos will release the mutex automatically
 }
+
+}