Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ConditionVariable.h Source File

ConditionVariable.h

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 #ifndef CONDITIONVARIABLE_H
00023 #define CONDITIONVARIABLE_H
00024 
00025 #include <stdint.h>
00026 #include "cmsis_os.h"
00027 #include "rtos/Mutex.h"
00028 #include "rtos/Semaphore.h"
00029 
00030 #include "platform/NonCopyable.h"
00031 
00032 namespace rtos {
00033 /** \addtogroup rtos */
00034 /** @{*/
00035 
00036 struct Waiter;
00037 
00038 /** This class provides a safe way to wait for or send notifications of condition changes
00039  *
00040  * This class is used in conjunction with a mutex to safely wait for or
00041  * notify waiters of condition changes to a resource accessible by multiple
00042  * threads.
00043  *
00044  * # Defined behavior
00045  * - All threads waiting on the condition variable wake when
00046  *   ConditionVariable::notify_all is called.
00047  * - If one or more threads are waiting on the condition variable at least
00048  *   one of them wakes when ConditionVariable::notify is called.
00049  *
00050  * # Undefined behavior
00051  * - The thread which is unblocked on ConditionVariable::notify_one is
00052  *   undefined if there are multiple waiters.
00053  * - The order which in which waiting threads acquire the condition variable's
00054  *   mutex after ConditionVariable::notify_all is called is undefined.
00055  * - When ConditionVariable::notify_one or ConditionVariable::notify_all is
00056  *   called and there are one or more waiters and one or more threads attempting
00057  *   to acquire the condition variable's mutex the order in which the mutex is
00058  *   acquired is undefined.
00059  * - The behavior of ConditionVariable::wait and ConditionVariable::wait_for
00060  *   is undefined if the condition variable's mutex is locked more than once by
00061  *   the calling thread.
00062  * - Spurious notifications (not triggered by the application) can occur
00063  *   and it is not defined when these occur.
00064  *
00065  * @note Synchronization level: Thread safe
00066  *
00067  * Example:
00068  * @code
00069  * #include "mbed.h"
00070  *
00071  * Mutex mutex;
00072  * ConditionVariable cond(mutex);
00073  *
00074  * // These variables are protected by locking mutex
00075  * uint32_t count = 0;
00076  * bool done = false;
00077  *
00078  * void worker_thread()
00079  * {
00080  *     mutex.lock();
00081  *     do {
00082  *         printf("Worker: Count %lu\r\n", count);
00083  *
00084  *         // Wait for a condition to change
00085  *         cond.wait();
00086  *
00087  *     } while (!done);
00088  *     printf("Worker: Exiting\r\n");
00089  *     mutex.unlock();
00090  * }
00091  *
00092  * int main() {
00093  *     Thread thread;
00094  *     thread.start(worker_thread);
00095  *
00096  *     for (int i = 0; i < 5; i++) {
00097  *
00098  *         mutex.lock();
00099  *         // Change count and notify waiters of this
00100  *         count++;
00101  *         printf("Main: Set count to %lu\r\n", count);
00102  *         cond.notify_all();
00103  *         mutex.unlock();
00104  *
00105  *         wait(1.0);
00106  *     }
00107  *
00108  *     mutex.lock();
00109  *     // Change done and notify waiters of this
00110  *     done = true;
00111  *     printf("Main: Set done\r\n");
00112  *     cond.notify_all();
00113  *     mutex.unlock();
00114  *
00115  *     thread.join();
00116  * }
00117  * @endcode
00118  */
00119 class ConditionVariable : private mbed::NonCopyable<ConditionVariable> {
00120 public:
00121     /** Create and Initialize a ConditionVariable object
00122      *
00123      * @note You cannot call this function from ISR context.
00124     */
00125     ConditionVariable(Mutex &mutex);
00126 
00127     /** Wait for a notification
00128      *
00129      * Wait until a notification occurs.
00130      *
00131      * @note - The thread calling this function must be the owner of the
00132      * ConditionVariable's mutex and it must be locked exactly once
00133      * @note - Spurious notifications can occur so the caller of this API
00134      * should check to make sure the condition they are waiting on has
00135      * been met
00136      *
00137      * Example:
00138      * @code
00139      * mutex.lock();
00140      * while (!condition_met) {
00141      *     cond.wait();
00142      * }
00143      *
00144      * function_to_handle_condition();
00145      *
00146      * mutex.unlock();
00147      * @endcode
00148      *
00149      * @note You cannot call this function from ISR context.
00150      */
00151     void wait();
00152 
00153     /** Wait for a notification until specified time
00154      *
00155      * @param   millisec  absolute end time referenced to Kernel::get_ms_count()
00156      * @return  true if a timeout occurred, false otherwise.
00157      *
00158      * @note - The thread calling this function must be the owner of the
00159      * ConditionVariable's mutex and it must be locked exactly once
00160      * @note - Spurious notifications can occur so the caller of this API
00161      * should check to make sure the condition they are waiting on has
00162      * been met
00163      *
00164      * Example:
00165      * @code
00166      * mutex.lock();
00167      * uint64_t end_time = Kernel::get_ms_count() + COND_WAIT_TIMEOUT;
00168      *
00169      * while (!condition_met) {
00170      *     if (cond.wait_until(end_time)) {
00171      *         break;
00172      *     }
00173      * }
00174      *
00175      * if (condition_met) {
00176      *     function_to_handle_condition();
00177      * }
00178      *
00179      * mutex.unlock();
00180      * @endcode
00181      *
00182      * @note You cannot call this function from ISR context.
00183      */
00184     bool wait_until(uint64_t millisec);
00185 
00186     /** Wait for a notification or timeout
00187      *
00188      * @param   millisec  timeout value or osWaitForever in case of no time-out.
00189      * @return  true if a timeout occurred, false otherwise.
00190      *
00191      * @note - The thread calling this function must be the owner of the
00192      * ConditionVariable's mutex and it must be locked exactly once
00193      * @note - Spurious notifications can occur so the caller of this API
00194      * should check to make sure the condition they are waiting on has
00195      * been met
00196      *
00197      * Example:
00198      * @code
00199      * mutex.lock();
00200      *
00201      * while (!condition_met) {
00202      *     cond.wait_for(MAX_SLEEP_TIME);
00203      *     if (!condition_met) {
00204      *         do_other_work_while_condition_false();
00205      *     }
00206      * }
00207      *
00208      * if (condition_met) {
00209      *     function_to_handle_condition();
00210      * }
00211      *
00212      * mutex.unlock();
00213      * @endcode
00214      *
00215      * @note You cannot call this function from ISR context.
00216      */
00217     bool wait_for(uint32_t millisec);
00218 
00219     /** Notify one waiter on this condition variable that a condition changed.
00220      *
00221      * @note - The thread calling this function must be the owner of the ConditionVariable's mutex
00222      *
00223      * @note You cannot call this function from ISR context.
00224      */
00225     void notify_one();
00226 
00227     /** Notify all waiters on this condition variable that a condition changed.
00228      *
00229      * @note - The thread calling this function must be the owner of the ConditionVariable's mutex
00230      *
00231      * @note You cannot call this function from ISR context.
00232      */
00233     void notify_all();
00234 
00235     /** ConditionVariable destructor
00236      *
00237      * @note You cannot call this function from ISR context.
00238      */
00239     ~ConditionVariable();
00240 
00241 protected:
00242     struct Waiter {
00243         Waiter();
00244         Semaphore sem;
00245         Waiter *prev;
00246         Waiter *next;
00247         bool in_list;
00248     };
00249 
00250     static void _add_wait_list(Waiter **wait_list, Waiter *waiter);
00251     static void _remove_wait_list(Waiter **wait_list, Waiter *waiter);
00252     Mutex &_mutex;
00253     Waiter *_wait_list;
00254 };
00255 
00256 }
00257 #endif
00258 
00259 /** @}*/