John Park | 33858a3 | 2018-09-28 23:05:48 -0700 | [diff] [blame] | 1 | #ifndef AOS_CONDITION_H_ |
| 2 | #define AOS_CONDITION_H_ |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 3 | |
Austin Schuh | 0ad2b6f | 2019-06-09 21:27:07 -0700 | [diff] [blame] | 4 | #include <chrono> |
| 5 | |
John Park | 398c74a | 2018-10-20 21:17:39 -0700 | [diff] [blame] | 6 | #include "aos/ipc_lib/aos_sync.h" |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 7 | |
| 8 | namespace aos { |
| 9 | |
Brian Silverman | dc1eb27 | 2014-08-19 14:25:59 -0400 | [diff] [blame] | 10 | class Mutex; |
| 11 | |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 12 | // A condition variable (IPC mechanism where 1 process/task can notify all |
Brian Silverman | eeb62ca | 2013-09-11 15:08:03 -0700 | [diff] [blame] | 13 | // others that are waiting for something to happen) without the race condition |
| 14 | // where a notification is sent after some process has checked if the thing has |
| 15 | // happened but before it has started listening for notifications. |
| 16 | // |
Brian Silverman | dc1eb27 | 2014-08-19 14:25:59 -0400 | [diff] [blame] | 17 | // This implementation will LOG(FATAL) if anything weird happens. |
Brian Silverman | eeb62ca | 2013-09-11 15:08:03 -0700 | [diff] [blame] | 18 | // |
| 19 | // A simple example of the use of a condition variable (adapted from |
| 20 | // pthread_cond(3)): |
| 21 | // |
| 22 | // int x, y; |
| 23 | // Mutex mutex; |
| 24 | // Condition condition(&mutex); |
| 25 | // |
| 26 | // // Waiting until x is greater than y: |
| 27 | // { |
| 28 | // MutexLocker locker(&mutex); |
| 29 | // while (!(x > y)) condition.Wait(); |
| 30 | // // do whatever |
| 31 | // } |
| 32 | // |
| 33 | // // Modifying x and/or y: |
| 34 | // { |
| 35 | // MutexLocker locker(&mutex); |
| 36 | // // modify x and y |
| 37 | // if (x > y) condition.Broadcast(); |
| 38 | // } |
| 39 | // |
| 40 | // Notice the loop around the Wait(). This is very important because some other |
| 41 | // process can lock the mutex and modify the shared state (possibly undoing |
| 42 | // whatever the Wait()er was waiting for) in between the Broadcast()er unlocking |
| 43 | // the mutex and the Wait()er(s) relocking it. |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 44 | // |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 45 | // Multiple condition variables may be associated with the same mutex but |
Brian Silverman | dc1eb27 | 2014-08-19 14:25:59 -0400 | [diff] [blame] | 46 | // exactly one mutex must be associated with each condition variable. |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 47 | class Condition { |
| 48 | public: |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 49 | // m is the mutex that will be associated with this condition variable. This |
| 50 | // object will hold on to a reference to it but does not take ownership. |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 51 | explicit Condition(Mutex *m); |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 52 | |
Austin Schuh | 0ad2b6f | 2019-06-09 21:27:07 -0700 | [diff] [blame] | 53 | enum class WaitResult { kOk, kOwnerDied, kTimeout }; |
| 54 | |
Brian Silverman | eeb62ca | 2013-09-11 15:08:03 -0700 | [diff] [blame] | 55 | // Waits for the condition variable to be signalled, atomically unlocking the |
| 56 | // mutex associated with this condition variable at the same time. The mutex |
| 57 | // associated with this condition variable must be locked when this is called |
| 58 | // and will be locked when this method returns. |
| 59 | // NOTE: The relocking of the mutex is not performed atomically with waking |
| 60 | // up. |
Brian Silverman | 71c55c5 | 2014-08-19 14:31:59 -0400 | [diff] [blame] | 61 | // Returns true if the previous owner of the mutex died before we relocked it. |
Brian Silverman | dc1eb27 | 2014-08-19 14:25:59 -0400 | [diff] [blame] | 62 | bool Wait() __attribute__((warn_unused_result)); |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 63 | |
Austin Schuh | 0ad2b6f | 2019-06-09 21:27:07 -0700 | [diff] [blame] | 64 | // Waits for the condition variable to be signalled with a timeout. |
| 65 | WaitResult WaitTimed(::std::chrono::nanoseconds timeout) |
| 66 | __attribute__((warn_unused_result)); |
| 67 | |
Brian Silverman | dc1eb27 | 2014-08-19 14:25:59 -0400 | [diff] [blame] | 68 | // Signals approximately 1 other process currently Wait()ing on this condition |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 69 | // variable. Calling this does not require the mutex associated with this |
| 70 | // condition variable to be locked. |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 71 | // One of the processes with the highest priority level will be woken. |
Brian Silverman | dc1eb27 | 2014-08-19 14:25:59 -0400 | [diff] [blame] | 72 | // If there aren't any waiting at the time, none will be woken. There is a |
| 73 | // small race condition in the Linux implementation that can result in more |
| 74 | // than 1 being woken. |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 75 | void Signal(); |
| 76 | // Wakes all processes that are currently Wait()ing on this condition |
| 77 | // variable. Calling this does not require the mutex associated with this |
| 78 | // condition variable to be locked. |
| 79 | void Broadcast(); |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 80 | |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 81 | // Retrieves the mutex associated with this condition variable. |
| 82 | Mutex *m() { return m_; } |
| 83 | |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 84 | private: |
Brian Silverman | dc1eb27 | 2014-08-19 14:25:59 -0400 | [diff] [blame] | 85 | aos_condition impl_; |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 86 | Mutex *m_; |
Brian Silverman | d41b442 | 2013-09-01 14:02:33 -0700 | [diff] [blame] | 87 | }; |
| 88 | |
| 89 | } // namespace aos |
| 90 | |
John Park | 33858a3 | 2018-09-28 23:05:48 -0700 | [diff] [blame] | 91 | #endif // AOS_CONDITION_H_ |