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