BBR 1 Ebene

Committer:
borlanic
Date:
Mon May 14 11:29:06 2018 +0000
Revision:
0:fbdae7e6d805
BBR

Who changed what in which revision?

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