| Index: native_client_sdk/src/libraries/nacl_io/event_listener.h | 
| diff --git a/native_client_sdk/src/libraries/nacl_io/event_listener.h b/native_client_sdk/src/libraries/nacl_io/event_listener.h | 
| index cb93f116b2f1b91179e78193ba8bb9551641c45a..4b9647a0b38bebae9469b44a764c2a7856404c89 100644 | 
| --- a/native_client_sdk/src/libraries/nacl_io/event_listener.h | 
| +++ b/native_client_sdk/src/libraries/nacl_io/event_listener.h | 
| @@ -15,6 +15,8 @@ | 
| #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 | 
| @@ -24,43 +26,43 @@ | 
| // down.  EventListener provides a mechanism for a thread to wait on | 
| // specific events from these objects which are derived from EventEmitters. | 
| // | 
| -// EventEmitter and EventListener together provide support for an "epoll" | 
| -// like interface.  See: | 
| -//     http://man7.org/linux/man-pages/man7/epoll.7.html | 
| +// 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. | 
| // | 
| -// Such that we map the arguments at behavior of | 
| -//     epoll_wait maps to Wait, and | 
| -//     epoll_ctl maps to Track, Update, Free. | 
| +// 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 | 
| // | 
| -//  Behavior of EventListeners | 
| -//    FDs are automatically removed when closed. | 
| -//    KE_SHUTDOWN can not be masked. | 
| -//    KE_SHUTDOWN is only seen if the hangup happens after Wait starts. | 
| -//    Dup'd FDs get their own event info which must also get signaled. | 
| -//    Adding a non streaming FD will fail. | 
| -//    EventEmitters can also be waited on. | 
| -//    It is illegal for an a EventListener to add itself. | 
| +// 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: | 
| -//    EventListener::{Track/Update/Free} | 
| -//      AUTO_LOCK(EventListener::info_lock_) | 
| -//       EventEmitter::RegisterEventInfo | 
| -//         AUTO_LOCK(EventEmitter::emitter_lock_) | 
| +//    EventEmitter::<Backgroun IO> | 
| +//      *LOCK* EventEmitter::emitter_lock_ | 
| +//        EventEmitter::RaiseEvent_Locked | 
| +//          EventListenerSingle::ReceiveEvents | 
| +//            <no locking, using emitter's lock> | 
| +//        EventListenerGroup::ReceiveEvents | 
| +//          *LOCK*  EventListenerGroup::signal_lock_ | 
| // | 
| -//    EventEmitter::Destroy | 
| -//      EventListener::AbandonedEventInfo | 
| -//        AUTO_LOCK(EventListener::info_lock_) | 
| +//    EventListenerSingle::WaitOnLock | 
| +//      *LOCK* EventEmitter::emitter_lock_ | 
| // | 
| -//    EventListener::RaiseEvent | 
| -//      AUTO_LOCK(EventEmitter::emitter_lock_) | 
| -//        EventListener::Signal | 
| -//          AUTO_LOCK(EventListener::signal_lock_) | 
| +//    EventListenerGroup::WaitOnAny | 
| +//      *LOCK* EventListenerGroup::signal_lock_ | 
| // | 
| -//    EventListener::Wait | 
| -//      AUTO_LOCK(EventListener::info_lock_) | 
| -//        ... | 
| -//      AUTO_LOCK(EventListener::signal_lock_) | 
| -//        ... | 
|  | 
| namespace nacl_io { | 
|  | 
| @@ -70,74 +72,95 @@ struct EventData { | 
| 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 EventEmitter { | 
| +class EventListener { | 
| public: | 
| -   EventListener(); | 
| -   ~EventListener(); | 
| +  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: | 
| -  // Called prior to free to unregister all EventInfos from the EventEmitters. | 
| -  void Destroy(); | 
| +  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: | 
| -   // Declared in EventEmitter | 
| -   virtual uint32_t GetEventStatus(); | 
| -   virtual int GetType(); | 
| - | 
| -   // Called by EventEmitter to signal the Listener that a new event is | 
| -   // available. | 
| -   void Signal(const ScopedEventInfo& info); | 
| - | 
| -   // Wait for one or more previously Tracked events to take place | 
| -   // or until ms_timeout expires, and fills |events| up to |max| limit. | 
| -   // The number of events recored is returned in |count|. | 
| -   Error Wait(EventData* events, int max, int ms_timeout, int* out_count); | 
| - | 
| -   // Tracks a new set of POLL events for a given unique |id|.  The | 
| -   // |user_data| will be returned in the Wait when an event of type |filter| | 
| -   // is received with that |id|. | 
| -   Error Track(int id, | 
| -               const ScopedEventEmitter& emitter, | 
| -               uint32_t filter, | 
| -               uint64_t user_data); | 
| - | 
| -   // Updates the tracking of events for |id|, replacing the |user_data| | 
| -   // that's returned, as well as which events will signal. | 
| -   Error Update(int id, uint32_t filter, uint64_t user_data); | 
| - | 
| -   // Unregisters the existing |id|. | 
| -   Error Free(int id); | 
| - | 
| -   // Notification by EventEmitter that it is abandoning the event.  Do not | 
| -   // access the emitter after this. | 
| -   void AbandonedEventInfo(const ScopedEventInfo& event); | 
| +  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); | 
| +}; | 
|  | 
| - private: | 
| -  // Protects the data in the EventInfo map. | 
| -  sdk_util::SimpleLock info_lock_; | 
|  | 
| -  // Map from ID to live a event info. | 
| -  EventInfoMap_t event_info_map_; | 
| +class EventListenerPoll : public EventListener { | 
| + public: | 
| +  EventListenerPoll() : EventListener(), signaled_(0) {} | 
|  | 
| -  // Protects waiting_, signaled_ and used with the signal_cond_. | 
| -  sdk_util::SimpleLock signal_lock_; | 
| -  pthread_cond_t signal_cond_; | 
| +  // Called by EventEmitter to signal the Listener that a new event is | 
| +  // available. | 
| +  virtual void ReceiveEvents(EventEmitter* emitter, uint32_t events); | 
|  | 
| -  // The number of threads currently waiting on this Listener. | 
| -  uint32_t waiting_; | 
| +  // 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); | 
|  | 
| -  // Set of event infos signaled during a wait. | 
| -  EventInfoSet_t signaled_; | 
| + private: | 
| +  sdk_util::SimpleLock signal_lock_; | 
| +  EmitterRequestMap_t emitters_; | 
| +  size_t signaled_; | 
| +  DISALLOW_COPY_AND_ASSIGN(EventListenerPoll); | 
| }; | 
|  | 
| -typedef sdk_util::ScopedRef<EventListener> ScopedEventListener; | 
| - | 
| }  // namespace nacl_io | 
|  | 
| #endif  /* LIBRARIES_NACL_IO_EVENT_LISTENER_H_ */ | 
|  |