Rtos API example

Committer:
marcozecchini
Date:
Sat Feb 23 12:13:36 2019 +0000
Revision:
0:9fca2b23d0ba
final commit

Who changed what in which revision?

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