Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ConditionVariable.cpp Source File

ConditionVariable.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017-2017 ARM Limited
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to deal
00006  * in the Software without restriction, including without limitation the rights
00007  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  * copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00020  * SOFTWARE.
00021  */
00022 #include "rtos/ConditionVariable.h"
00023 #include "rtos/Kernel.h"
00024 #include "rtos/ThisThread.h"
00025 
00026 #include "platform/mbed_error.h"
00027 #include "platform/mbed_assert.h"
00028 
00029 #if MBED_CONF_RTOS_PRESENT
00030 
00031 namespace rtos {
00032 
00033 ConditionVariable::Waiter::Waiter(): sem(0), prev(nullptr), next(nullptr), in_list(false)
00034 {
00035     // No initialization to do
00036 }
00037 
00038 ConditionVariable::ConditionVariable(Mutex &mutex): _mutex(mutex), _wait_list(nullptr)
00039 {
00040     // No initialization to do
00041 }
00042 
00043 void ConditionVariable::wait()
00044 {
00045     wait_for(osWaitForever);
00046 }
00047 
00048 bool ConditionVariable::wait_for(uint32_t millisec)
00049 {
00050     Waiter current_thread;
00051     MBED_ASSERT(_mutex.get_owner() == ThisThread::get_id());
00052     MBED_ASSERT(_mutex._count == 1);
00053     _add_wait_list(&_wait_list, &current_thread);
00054 
00055     _mutex.unlock();
00056 
00057     bool timeout = !current_thread.sem.try_acquire_for(millisec);
00058 
00059     _mutex.lock();
00060 
00061     if (current_thread.in_list) {
00062         _remove_wait_list(&_wait_list, &current_thread);
00063     }
00064 
00065     return timeout;
00066 }
00067 
00068 bool ConditionVariable::wait_until(uint64_t millisec)
00069 {
00070     uint64_t now = Kernel::get_ms_count();
00071 
00072     if (now >= millisec) {
00073         // Time has already passed - standard behaviour is to
00074         // treat as a "try".
00075         return wait_for(0);
00076     } else if (millisec - now >= osWaitForever) {
00077         // Exceeds maximum delay of underlying wait_for -
00078         // spuriously wake after 49 days, indicating no timeout.
00079         wait_for(osWaitForever - 1);
00080         return false;
00081     } else {
00082         return wait_for(millisec - now);
00083     }
00084 }
00085 
00086 void ConditionVariable::notify_one()
00087 {
00088     MBED_ASSERT(_mutex.get_owner() == ThisThread::get_id());
00089     if (_wait_list != nullptr) {
00090         _wait_list->sem.release();
00091         _remove_wait_list(&_wait_list, _wait_list);
00092     }
00093 }
00094 
00095 void ConditionVariable::notify_all()
00096 {
00097     MBED_ASSERT(_mutex.get_owner() == ThisThread::get_id());
00098     while (_wait_list != nullptr) {
00099         _wait_list->sem.release();
00100         _remove_wait_list(&_wait_list, _wait_list);
00101     }
00102 }
00103 
00104 void ConditionVariable::_add_wait_list(Waiter **wait_list, Waiter *waiter)
00105 {
00106     if (nullptr == *wait_list) {
00107         // Nothing in the list so add it directly.
00108         // Update prev and next pointer to reference self
00109         *wait_list = waiter;
00110         waiter->next = waiter;
00111         waiter->prev = waiter;
00112     } else {
00113         // Add after the last element
00114         Waiter *first = *wait_list;
00115         Waiter *last = (*wait_list)->prev;
00116 
00117         // Update new entry
00118         waiter->next = first;
00119         waiter->prev = last;
00120 
00121         // Insert into the list
00122         first->prev = waiter;
00123         last->next = waiter;
00124     }
00125     waiter->in_list = true;
00126 }
00127 
00128 void ConditionVariable::_remove_wait_list(Waiter **wait_list, Waiter *waiter)
00129 {
00130     Waiter *prev = waiter->prev;
00131     Waiter *next = waiter->next;
00132 
00133     // Remove from list
00134     prev->next = waiter->next;
00135     next->prev = waiter->prev;
00136     *wait_list = waiter->next;
00137 
00138     if (*wait_list == waiter) {
00139         // This was the last element in the list
00140         *wait_list = nullptr;
00141     }
00142 
00143     // Invalidate pointers
00144     waiter->next = nullptr;
00145     waiter->prev = nullptr;
00146     waiter->in_list = false;
00147 }
00148 
00149 ConditionVariable::~ConditionVariable()
00150 {
00151     MBED_ASSERT(nullptr == _wait_list);
00152 }
00153 
00154 }
00155 
00156 #endif