/* 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_; uint32_t events_; 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_ */