RTC auf true

Committer:
kevman
Date:
Wed Nov 28 15:10:15 2018 +0000
Revision:
0:38ceb79fef03
RTC modified

Who changed what in which revision?

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