BA / SerialCom

Fork of OmniWheels by Gustav Atmel

Committer:
gustavatmel
Date:
Tue May 01 15:47:08 2018 +0000
Revision:
1:9c5af431a1f1
sdf

Who changed what in which revision?

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