Nicolas Borla / Mbed OS ROME2_Robot_Firmware
Committer:
boro
Date:
Mon Mar 16 13:12:31 2020 +0000
Revision:
0:4beb2ea291ec
a

Who changed what in which revision?

UserRevisionLine numberNew contents of line
boro 0:4beb2ea291ec 1 /* mbed Microcontroller Library
boro 0:4beb2ea291ec 2 * Copyright (c) 2017-2017 ARM Limited
boro 0:4beb2ea291ec 3 *
boro 0:4beb2ea291ec 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
boro 0:4beb2ea291ec 5 * of this software and associated documentation files (the "Software"), to deal
boro 0:4beb2ea291ec 6 * in the Software without restriction, including without limitation the rights
boro 0:4beb2ea291ec 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
boro 0:4beb2ea291ec 8 * copies of the Software, and to permit persons to whom the Software is
boro 0:4beb2ea291ec 9 * furnished to do so, subject to the following conditions:
boro 0:4beb2ea291ec 10 *
boro 0:4beb2ea291ec 11 * The above copyright notice and this permission notice shall be included in
boro 0:4beb2ea291ec 12 * all copies or substantial portions of the Software.
boro 0:4beb2ea291ec 13 *
boro 0:4beb2ea291ec 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
boro 0:4beb2ea291ec 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
boro 0:4beb2ea291ec 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
boro 0:4beb2ea291ec 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
boro 0:4beb2ea291ec 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
boro 0:4beb2ea291ec 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
boro 0:4beb2ea291ec 20 * SOFTWARE.
boro 0:4beb2ea291ec 21 */
boro 0:4beb2ea291ec 22 #ifndef CONDITIONVARIABLE_H
boro 0:4beb2ea291ec 23 #define CONDITIONVARIABLE_H
boro 0:4beb2ea291ec 24
boro 0:4beb2ea291ec 25 #include <stdint.h>
boro 0:4beb2ea291ec 26 #include "cmsis_os.h"
boro 0:4beb2ea291ec 27 #include "rtos/Mutex.h"
boro 0:4beb2ea291ec 28 #include "rtos/Semaphore.h"
boro 0:4beb2ea291ec 29
boro 0:4beb2ea291ec 30 #include "platform/NonCopyable.h"
boro 0:4beb2ea291ec 31
boro 0:4beb2ea291ec 32 namespace rtos {
boro 0:4beb2ea291ec 33 /** \addtogroup rtos */
boro 0:4beb2ea291ec 34 /** @{*/
boro 0:4beb2ea291ec 35
boro 0:4beb2ea291ec 36 struct Waiter;
boro 0:4beb2ea291ec 37
boro 0:4beb2ea291ec 38 /** This class provides a safe way to wait for or send notifications of condition changes
boro 0:4beb2ea291ec 39 *
boro 0:4beb2ea291ec 40 * This class is used in conjunction with a mutex to safely wait for or
boro 0:4beb2ea291ec 41 * notify waiters of condition changes to a resource accessible by multiple
boro 0:4beb2ea291ec 42 * threads.
boro 0:4beb2ea291ec 43 *
boro 0:4beb2ea291ec 44 * # Defined behavior
boro 0:4beb2ea291ec 45 * - All threads waiting on the condition variable wake when
boro 0:4beb2ea291ec 46 * ConditionVariable::notify_all is called.
boro 0:4beb2ea291ec 47 * - If one or more threads are waiting on the condition variable at least
boro 0:4beb2ea291ec 48 * one of them wakes when ConditionVariable::notify is called.
boro 0:4beb2ea291ec 49 *
boro 0:4beb2ea291ec 50 * # Undefined behavior
boro 0:4beb2ea291ec 51 * - The thread which is unblocked on ConditionVariable::notify_one is
boro 0:4beb2ea291ec 52 * undefined if there are multiple waiters.
boro 0:4beb2ea291ec 53 * - The order which in which waiting threads acquire the condition variable's
boro 0:4beb2ea291ec 54 * mutex after ConditionVariable::notify_all is called is undefined.
boro 0:4beb2ea291ec 55 * - When ConditionVariable::notify_one or ConditionVariable::notify_all is
boro 0:4beb2ea291ec 56 * called and there are one or more waiters and one or more threads attempting
boro 0:4beb2ea291ec 57 * to acquire the condition variable's mutex the order in which the mutex is
boro 0:4beb2ea291ec 58 * acquired is undefined.
boro 0:4beb2ea291ec 59 * - The behavior of ConditionVariable::wait and ConditionVariable::wait_for
boro 0:4beb2ea291ec 60 * is undefined if the condition variable's mutex is locked more than once by
boro 0:4beb2ea291ec 61 * the calling thread.
boro 0:4beb2ea291ec 62 * - Spurious notifications (not triggered by the application) can occur
boro 0:4beb2ea291ec 63 * and it is not defined when these occur.
boro 0:4beb2ea291ec 64 *
boro 0:4beb2ea291ec 65 * @note Synchronization level: Thread safe
boro 0:4beb2ea291ec 66 *
boro 0:4beb2ea291ec 67 * Example:
boro 0:4beb2ea291ec 68 * @code
boro 0:4beb2ea291ec 69 * #include "mbed.h"
boro 0:4beb2ea291ec 70 *
boro 0:4beb2ea291ec 71 * Mutex mutex;
boro 0:4beb2ea291ec 72 * ConditionVariable cond(mutex);
boro 0:4beb2ea291ec 73 *
boro 0:4beb2ea291ec 74 * // These variables are protected by locking mutex
boro 0:4beb2ea291ec 75 * uint32_t count = 0;
boro 0:4beb2ea291ec 76 * bool done = false;
boro 0:4beb2ea291ec 77 *
boro 0:4beb2ea291ec 78 * void worker_thread()
boro 0:4beb2ea291ec 79 * {
boro 0:4beb2ea291ec 80 * mutex.lock();
boro 0:4beb2ea291ec 81 * do {
boro 0:4beb2ea291ec 82 * printf("Worker: Count %lu\r\n", count);
boro 0:4beb2ea291ec 83 *
boro 0:4beb2ea291ec 84 * // Wait for a condition to change
boro 0:4beb2ea291ec 85 * cond.wait();
boro 0:4beb2ea291ec 86 *
boro 0:4beb2ea291ec 87 * } while (!done);
boro 0:4beb2ea291ec 88 * printf("Worker: Exiting\r\n");
boro 0:4beb2ea291ec 89 * mutex.unlock();
boro 0:4beb2ea291ec 90 * }
boro 0:4beb2ea291ec 91 *
boro 0:4beb2ea291ec 92 * int main() {
boro 0:4beb2ea291ec 93 * Thread thread;
boro 0:4beb2ea291ec 94 * thread.start(worker_thread);
boro 0:4beb2ea291ec 95 *
boro 0:4beb2ea291ec 96 * for (int i = 0; i < 5; i++) {
boro 0:4beb2ea291ec 97 *
boro 0:4beb2ea291ec 98 * mutex.lock();
boro 0:4beb2ea291ec 99 * // Change count and notify waiters of this
boro 0:4beb2ea291ec 100 * count++;
boro 0:4beb2ea291ec 101 * printf("Main: Set count to %lu\r\n", count);
boro 0:4beb2ea291ec 102 * cond.notify_all();
boro 0:4beb2ea291ec 103 * mutex.unlock();
boro 0:4beb2ea291ec 104 *
boro 0:4beb2ea291ec 105 * wait(1.0);
boro 0:4beb2ea291ec 106 * }
boro 0:4beb2ea291ec 107 *
boro 0:4beb2ea291ec 108 * mutex.lock();
boro 0:4beb2ea291ec 109 * // Change done and notify waiters of this
boro 0:4beb2ea291ec 110 * done = true;
boro 0:4beb2ea291ec 111 * printf("Main: Set done\r\n");
boro 0:4beb2ea291ec 112 * cond.notify_all();
boro 0:4beb2ea291ec 113 * mutex.unlock();
boro 0:4beb2ea291ec 114 *
boro 0:4beb2ea291ec 115 * thread.join();
boro 0:4beb2ea291ec 116 * }
boro 0:4beb2ea291ec 117 * @endcode
boro 0:4beb2ea291ec 118 */
boro 0:4beb2ea291ec 119 class ConditionVariable : private mbed::NonCopyable<ConditionVariable> {
boro 0:4beb2ea291ec 120 public:
boro 0:4beb2ea291ec 121 /** Create and Initialize a ConditionVariable object */
boro 0:4beb2ea291ec 122 ConditionVariable(Mutex &mutex);
boro 0:4beb2ea291ec 123
boro 0:4beb2ea291ec 124 /** Wait for a notification
boro 0:4beb2ea291ec 125 *
boro 0:4beb2ea291ec 126 * Wait until a notification occurs.
boro 0:4beb2ea291ec 127 *
boro 0:4beb2ea291ec 128 * @note - The thread calling this function must be the owner of the
boro 0:4beb2ea291ec 129 * ConditionVariable's mutex and it must be locked exactly once
boro 0:4beb2ea291ec 130 * @note - Spurious notifications can occur so the caller of this API
boro 0:4beb2ea291ec 131 * should check to make sure the condition they are waiting on has
boro 0:4beb2ea291ec 132 * been met
boro 0:4beb2ea291ec 133 *
boro 0:4beb2ea291ec 134 * Example:
boro 0:4beb2ea291ec 135 * @code
boro 0:4beb2ea291ec 136 * mutex.lock();
boro 0:4beb2ea291ec 137 * while (!condition_met) {
boro 0:4beb2ea291ec 138 * cond.wait();
boro 0:4beb2ea291ec 139 * }
boro 0:4beb2ea291ec 140 *
boro 0:4beb2ea291ec 141 * function_to_handle_condition();
boro 0:4beb2ea291ec 142 *
boro 0:4beb2ea291ec 143 * mutex.unlock();
boro 0:4beb2ea291ec 144 * @endcode
boro 0:4beb2ea291ec 145 */
boro 0:4beb2ea291ec 146 void wait();
boro 0:4beb2ea291ec 147
boro 0:4beb2ea291ec 148 /** Wait for a notification or timeout
boro 0:4beb2ea291ec 149 *
boro 0:4beb2ea291ec 150 * @param millisec timeout value or osWaitForever in case of no time-out.
boro 0:4beb2ea291ec 151 * @return true if a timeout occurred, false otherwise.
boro 0:4beb2ea291ec 152 *
boro 0:4beb2ea291ec 153 * @note - The thread calling this function must be the owner of the
boro 0:4beb2ea291ec 154 * ConditionVariable's mutex and it must be locked exactly once
boro 0:4beb2ea291ec 155 * @note - Spurious notifications can occur so the caller of this API
boro 0:4beb2ea291ec 156 * should check to make sure the condition they are waiting on has
boro 0:4beb2ea291ec 157 * been met
boro 0:4beb2ea291ec 158 *
boro 0:4beb2ea291ec 159 * Example:
boro 0:4beb2ea291ec 160 * @code
boro 0:4beb2ea291ec 161 * mutex.lock();
boro 0:4beb2ea291ec 162 * Timer timer;
boro 0:4beb2ea291ec 163 * timer.start();
boro 0:4beb2ea291ec 164 *
boro 0:4beb2ea291ec 165 * bool timed_out = false;
boro 0:4beb2ea291ec 166 * uint32_t time_left = TIMEOUT;
boro 0:4beb2ea291ec 167 * while (!condition_met && !timed_out) {
boro 0:4beb2ea291ec 168 * timed_out = cond.wait_for(time_left);
boro 0:4beb2ea291ec 169 * uint32_t elapsed = timer.read_ms();
boro 0:4beb2ea291ec 170 * time_left = elapsed > TIMEOUT ? 0 : TIMEOUT - elapsed;
boro 0:4beb2ea291ec 171 * }
boro 0:4beb2ea291ec 172 *
boro 0:4beb2ea291ec 173 * if (condition_met) {
boro 0:4beb2ea291ec 174 * function_to_handle_condition();
boro 0:4beb2ea291ec 175 * }
boro 0:4beb2ea291ec 176 *
boro 0:4beb2ea291ec 177 * mutex.unlock();
boro 0:4beb2ea291ec 178 * @endcode
boro 0:4beb2ea291ec 179 */
boro 0:4beb2ea291ec 180 bool wait_for(uint32_t millisec);
boro 0:4beb2ea291ec 181
boro 0:4beb2ea291ec 182 /** Notify one waiter on this condition variable that a condition changed.
boro 0:4beb2ea291ec 183 *
boro 0:4beb2ea291ec 184 * @note - The thread calling this function must be the owner of the ConditionVariable's mutex
boro 0:4beb2ea291ec 185 */
boro 0:4beb2ea291ec 186 void notify_one();
boro 0:4beb2ea291ec 187
boro 0:4beb2ea291ec 188 /** Notify all waiters on this condition variable that a condition changed.
boro 0:4beb2ea291ec 189 *
boro 0:4beb2ea291ec 190 * @note - The thread calling this function must be the owner of the ConditionVariable's mutex
boro 0:4beb2ea291ec 191 */
boro 0:4beb2ea291ec 192 void notify_all();
boro 0:4beb2ea291ec 193
boro 0:4beb2ea291ec 194 ~ConditionVariable();
boro 0:4beb2ea291ec 195
boro 0:4beb2ea291ec 196 protected:
boro 0:4beb2ea291ec 197 struct Waiter {
boro 0:4beb2ea291ec 198 Waiter();
boro 0:4beb2ea291ec 199 Semaphore sem;
boro 0:4beb2ea291ec 200 Waiter *prev;
boro 0:4beb2ea291ec 201 Waiter *next;
boro 0:4beb2ea291ec 202 bool in_list;
boro 0:4beb2ea291ec 203 };
boro 0:4beb2ea291ec 204
boro 0:4beb2ea291ec 205 static void _add_wait_list(Waiter **wait_list, Waiter *waiter);
boro 0:4beb2ea291ec 206 static void _remove_wait_list(Waiter **wait_list, Waiter *waiter);
boro 0:4beb2ea291ec 207 Mutex &_mutex;
boro 0:4beb2ea291ec 208 Waiter *_wait_list;
boro 0:4beb2ea291ec 209 };
boro 0:4beb2ea291ec 210
boro 0:4beb2ea291ec 211 }
boro 0:4beb2ea291ec 212 #endif
boro 0:4beb2ea291ec 213
boro 0:4beb2ea291ec 214 /** @}*/