| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIBRARIES_NACL_IO_EVENT_LISTENER_H_ |
| #define LIBRARIES_NACL_IO_EVENT_LISTENER_H_ |
| |
| #include <pthread.h> |
| |
| #include <map> |
| #include <set> |
| #include <vector> |
| |
| #include "nacl_io/error.h" |
| #include "nacl_io/event_emitter.h" |
| |
| #include "sdk_util/auto_lock.h" |
| #include "sdk_util/macros.h" |
| #include "sdk_util/scoped_ref.h" |
| |
| // Kernel Events |
| // |
| // Certain file objects such as pipes or sockets can become signaled when |
| // read or write buffers become available, or when the connection is torn |
| // down. EventListener provides a mechanism for a thread to wait on |
| // specific events from these objects which are derived from EventEmitters. |
| // |
| // Calling RegisterListener_Locked on an event emitter, will cause all |
| // Listeners matching the event mask are signaled so they may try to make |
| // progress. In the case of "select" or "poll", multiple threads could be |
| // notified that one or more emitters are signaled and allowed to make |
| // progress. In the case of "read" or "write", only one thread at a time |
| // should make progress, to ensure that if one thread consumes the signal, |
| // the other can correctly timeout. |
| // |
| // Events Listeners requirements: |
| // 1- Must reference counting Emitters to ensure they are not destroyed |
| // while waiting for a signal. |
| // 2- Must unregister themselves from all emitters prior to being destoryed. |
| // 3- Must never be shared between threads since interals may not be locked |
| // to prevent dead-locks with emitter signals. |
| // 4- Must never lock themselves before locking an emitter to prevent |
| // dead-locks |
| // |
| // There are two types of listeners, EventListenerSingle and EventListenerGroup |
| // For Single listeners, all listeners are unblocked by the Emitter, but |
| // they individually take the emitters lock and test against the current |
| // status to ensure another listener didn't consume the signal. |
| // |
| // Locking: |
| // EventEmitter::<Backgroun IO> |
| // *LOCK* EventEmitter::emitter_lock_ |
| // EventEmitter::RaiseEvent_Locked |
| // EventListenerSingle::ReceiveEvents |
| // <no locking, using emitter's lock> |
| // EventListenerGroup::ReceiveEvents |
| // *LOCK* EventListenerGroup::signal_lock_ |
| // |
| // EventListenerSingle::WaitOnLock |
| // *LOCK* EventEmitter::emitter_lock_ |
| // |
| // EventListenerGroup::WaitOnAny |
| // *LOCK* EventListenerGroup::signal_lock_ |
| // |
| |
| namespace nacl_io { |
| |
| struct EventData { |
| // Bit Mask of signaled POLL events. |
| uint32_t events; |
| uint64_t user_data; |
| }; |
| |
| struct EventRequest { |
| ScopedEventEmitter emitter; |
| uint32_t filter; |
| uint32_t events; |
| }; |
| |
| class EventListener; |
| class EventListenerGroup; |
| class EventListenerSingle; |
| |
| typedef std::map<EventEmitter*, EventRequest*> EmitterRequestMap_t; |
| |
| // EventListener |
| // |
| // The EventListener class provides an object to wait on for specific events |
| // from EventEmitter objects. The EventListener becomes signalled for |
| // read when events are waiting, making it is also an Emitter. |
| class EventListener { |
| public: |
| EventListener(); |
| ~EventListener(); |
| |
| // Called by EventEmitter to signal the Listener that a new event is |
| // available. |
| virtual void ReceiveEvents(EventEmitter* emitter, uint32_t events) = 0; |
| |
| protected: |
| pthread_cond_t signal_cond_; |
| DISALLOW_COPY_AND_ASSIGN(EventListener); |
| }; |
| |
| // EventListenerLock |
| // |
| // On construction, references and locks the emitter. WaitOnEvent will |
| // temporarily unlock waiting for any event in |events| to become signaled. |
| // The functione exits with the lock taken. The destructor will automatically |
| // unlock the emitter. |
| class EventListenerLock : public EventListener { |
| public: |
| explicit EventListenerLock(EventEmitter* emitter); |
| ~EventListenerLock(); |
| |
| // Called by EventEmitter to signal the Listener that a new event is |
| // available. |
| virtual void ReceiveEvents(EventEmitter* emitter, uint32_t events); |
| |
| // Called with the emitters lock held (which happens in the constructor). |
| // Waits in a condvar until one of the events in |events| is raised or |
| // or the timeout expired. Returns with the emitter lock held, which |
| // will be release when the destructor is called. |
| // |
| // On Error: |
| // ETIMEOUT if the timeout is exceeded. |
| // EINTR if the wait was interrupted. |
| Error WaitOnEvent(uint32_t events, int ms_max); |
| |
| private: |
| EventEmitter* emitter_; |
| sdk_util::AutoLock* lock_; |
| DISALLOW_COPY_AND_ASSIGN(EventListenerLock); |
| }; |
| |
| class EventListenerPoll : public EventListener { |
| public: |
| EventListenerPoll() : EventListener(), signaled_(0) {} |
| |
| // Called by EventEmitter to signal the Listener that a new event is |
| // available. |
| virtual void ReceiveEvents(EventEmitter* emitter, uint32_t events); |
| |
| // Wait for the any requested emitter/filter pairs to emit one of the |
| // events in the matching filter. Returns 0 on success. |
| // |
| // On Error: |
| // ETIMEOUT if the timeout is exceeded. |
| // EINTR if the wait was interrupted. |
| Error WaitOnAny(EventRequest* requests, size_t cnt, int ms_max); |
| |
| private: |
| sdk_util::SimpleLock signal_lock_; |
| EmitterRequestMap_t emitters_; |
| size_t signaled_; |
| DISALLOW_COPY_AND_ASSIGN(EventListenerPoll); |
| }; |
| |
| } // namespace nacl_io |
| |
| #endif // LIBRARIES_NACL_IO_EVENT_LISTENER_H_ |