| #ifndef AOS_CONDITION_H_ |
| #define AOS_CONDITION_H_ |
| |
| #include <chrono> |
| |
| #include "aos/ipc_lib/aos_sync.h" |
| |
| namespace aos { |
| |
| class Mutex; |
| |
| // A condition variable (IPC mechanism where 1 process/task can notify all |
| // others that are waiting for something to happen) without the race condition |
| // where a notification is sent after some process has checked if the thing has |
| // happened but before it has started listening for notifications. |
| // |
| // This implementation will LOG(FATAL) if anything weird happens. |
| // |
| // A simple example of the use of a condition variable (adapted from |
| // pthread_cond(3)): |
| // |
| // int x, y; |
| // Mutex mutex; |
| // Condition condition(&mutex); |
| // |
| // // Waiting until x is greater than y: |
| // { |
| // MutexLocker locker(&mutex); |
| // while (!(x > y)) condition.Wait(); |
| // // do whatever |
| // } |
| // |
| // // Modifying x and/or y: |
| // { |
| // MutexLocker locker(&mutex); |
| // // modify x and y |
| // if (x > y) condition.Broadcast(); |
| // } |
| // |
| // Notice the loop around the Wait(). This is very important because some other |
| // process can lock the mutex and modify the shared state (possibly undoing |
| // whatever the Wait()er was waiting for) in between the Broadcast()er unlocking |
| // the mutex and the Wait()er(s) relocking it. |
| // |
| // Multiple condition variables may be associated with the same mutex but |
| // exactly one mutex must be associated with each condition variable. |
| class Condition { |
| public: |
| // m is the mutex that will be associated with this condition variable. This |
| // object will hold on to a reference to it but does not take ownership. |
| explicit Condition(Mutex *m); |
| |
| enum class WaitResult { kOk, kOwnerDied, kTimeout }; |
| |
| // Waits for the condition variable to be signalled, atomically unlocking the |
| // mutex associated with this condition variable at the same time. The mutex |
| // associated with this condition variable must be locked when this is called |
| // and will be locked when this method returns. |
| // NOTE: The relocking of the mutex is not performed atomically with waking |
| // up. |
| // Returns true if the previous owner of the mutex died before we relocked it. |
| bool Wait() __attribute__((warn_unused_result)); |
| |
| // Waits for the condition variable to be signalled with a timeout. |
| WaitResult WaitTimed(::std::chrono::nanoseconds timeout) |
| __attribute__((warn_unused_result)); |
| |
| // Signals approximately 1 other process currently Wait()ing on this condition |
| // variable. Calling this does not require the mutex associated with this |
| // condition variable to be locked. |
| // One of the processes with the highest priority level will be woken. |
| // If there aren't any waiting at the time, none will be woken. There is a |
| // small race condition in the Linux implementation that can result in more |
| // than 1 being woken. |
| void Signal(); |
| // Wakes all processes that are currently Wait()ing on this condition |
| // variable. Calling this does not require the mutex associated with this |
| // condition variable to be locked. |
| void Broadcast(); |
| |
| // Retrieves the mutex associated with this condition variable. |
| Mutex *m() { return m_; } |
| |
| private: |
| aos_condition impl_; |
| Mutex *m_; |
| }; |
| |
| } // namespace aos |
| |
| #endif // AOS_CONDITION_H_ |