1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 #ifndef BASE_MESSAGE_PUMP_LIBEVENT_H_ 8 #define BASE_MESSAGE_PUMP_LIBEVENT_H_ 9 10 #include "base/message_pump.h" 11 #include "base/time.h" 12 #include "mozilla/UniquePtr.h" 13 #include "nsStringFwd.h" 14 15 // Declare structs we need from libevent.h rather than including it 16 struct event_base; 17 struct event; 18 19 namespace base { 20 21 // Class to monitor sockets and issue callbacks when sockets are ready for I/O 22 // TODO(dkegel): add support for background file IO somehow 23 class MessagePumpLibevent : public MessagePump { 24 public: 25 // Object returned by WatchFileDescriptor to manage further watching. 26 class FileDescriptorWatcher { 27 public: 28 FileDescriptorWatcher(); 29 ~FileDescriptorWatcher(); // Implicitly calls StopWatchingFileDescriptor. 30 31 // NOTE: These methods aren't called StartWatching()/StopWatching() to 32 // avoid confusion with the win32 ObjectWatcher class. 33 34 // Stop watching the FD, always safe to call. No-op if there's nothing 35 // to do. 36 bool StopWatchingFileDescriptor(); 37 38 private: 39 // Called by MessagePumpLibevent, ownership of |e| is transferred to this 40 // object. 41 void Init(event* e, bool is_persistent); 42 43 // Used by MessagePumpLibevent to take ownership of event_. 44 event* ReleaseEvent(); 45 friend class MessagePumpLibevent; 46 47 private: 48 bool is_persistent_; // false if this event is one-shot. 49 event* event_; 50 DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher); 51 }; 52 53 // Used with WatchFileDescptor to asynchronously monitor the I/O readiness of 54 // a File Descriptor. 55 class Watcher { 56 public: ~Watcher()57 virtual ~Watcher() {} 58 // Called from MessageLoop::Run when an FD can be read from/written to 59 // without blocking 60 virtual void OnFileCanReadWithoutBlocking(int fd) = 0; 61 virtual void OnFileCanWriteWithoutBlocking(int fd) = 0; 62 }; 63 64 MessagePumpLibevent(); 65 66 enum Mode { 67 WATCH_READ = 1 << 0, 68 WATCH_WRITE = 1 << 1, 69 WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE 70 }; 71 72 // Have the current thread's message loop watch for a a situation in which 73 // reading/writing to the FD can be performed without Blocking. 74 // Callers must provide a preallocated FileDescriptorWatcher object which 75 // can later be used to manage the Lifetime of this event. 76 // If a FileDescriptorWatcher is passed in which is already attached to 77 // an event, then the effect is cumulative i.e. after the call |controller| 78 // will watch both the previous event and the new one. 79 // If an error occurs while calling this method in a cumulative fashion, the 80 // event previously attached to |controller| is aborted. 81 // Returns true on success. 82 // TODO(dkegel): switch to edge-triggered readiness notification 83 bool WatchFileDescriptor(int fd, bool persistent, Mode mode, 84 FileDescriptorWatcher* controller, 85 Watcher* delegate); 86 87 // This is analagous to FileDescriptorWatcher above, which really is 88 // just a wrapper around libevent's |struct event|. This class acts 89 // as a sort of "scoped event watcher" in that it guarantees that 90 // when this class is out of scope, the signal-event it wraps is 91 // removed from libevent's guts. 92 // 93 // XXX/cjones: this isn't my favorite API, but preserving it in 94 // order to match code above 95 class SignalEvent { 96 friend class MessagePumpLibevent; 97 98 public: 99 SignalEvent(); 100 ~SignalEvent(); // implicitly calls StopCatching() 101 102 // Have libevent forget this event. 103 bool StopCatching(); 104 105 private: 106 void Init(event* e); 107 event* ReleaseEvent(); 108 109 event* event_; 110 111 DISALLOW_COPY_AND_ASSIGN(SignalEvent); 112 }; 113 114 class SignalWatcher { 115 public: ~SignalWatcher()116 virtual ~SignalWatcher() {} 117 // Called from MessageLoop::Run when |sig| has been delivered to 118 // this process 119 virtual void OnSignal(int sig) = 0; 120 }; 121 122 // Have the current thread's message loop catch the signal |sig|. 123 // Multiple watchers can catch the same signal; they're all notified 124 // upon its delivery. Callers must provide a preallocated 125 // SignalEvent object which can be used to manage the lifetime of 126 // this event. Returns true on success. 127 bool CatchSignal(int sig, SignalEvent* sigevent, SignalWatcher* delegate); 128 129 // MessagePump methods: 130 virtual void Run(Delegate* delegate) override; 131 virtual void Quit() override; 132 virtual void ScheduleWork() override; 133 virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override; 134 135 protected: 136 virtual ~MessagePumpLibevent(); 137 138 private: 139 // Risky part of constructor. Returns true on success. 140 bool Init(); 141 142 // This flag is set to false when Run should return. 143 bool keep_running_; 144 145 // This flag is set when inside Run. 146 bool in_run_; 147 148 // The time at which we should call DoDelayedWork. 149 TimeTicks delayed_work_time_; 150 151 // Libevent dispatcher. Watches all sockets registered with it, and sends 152 // readiness callbacks when a socket is ready for I/O. 153 event_base* event_base_; 154 155 // Called by libevent to tell us a registered FD can be read/written to. 156 static void OnLibeventNotification(int fd, short flags, void* context); 157 158 // Called by libevent upon receiving a signal 159 static void OnLibeventSignalNotification(int sig, short flags, void* context); 160 161 // Unix pipe used to implement ScheduleWork() 162 // ... callback; called by libevent inside Run() when pipe is ready to read 163 static void OnWakeup(int socket, short flags, void* context); 164 // ... write end; ScheduleWork() writes a single byte to it 165 int wakeup_pipe_in_; 166 // ... read end; OnWakeup reads it and then breaks Run() out of its sleep 167 int wakeup_pipe_out_; 168 // ... libevent wrapper for read end 169 event* wakeup_event_; 170 171 DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent); 172 }; 173 174 /** 175 * LineWatcher overrides OnFileCanReadWithoutBlocking. It separates the read 176 * data by mTerminator and passes each line to OnLineRead. 177 */ 178 class LineWatcher : public MessagePumpLibevent::Watcher { 179 public: LineWatcher(char aTerminator,int aBufferSize)180 LineWatcher(char aTerminator, int aBufferSize) 181 : mReceivedIndex(0), mBufferSize(aBufferSize), mTerminator(aTerminator) { 182 mReceiveBuffer = mozilla::MakeUnique<char[]>(mBufferSize); 183 } 184 ~LineWatcher()185 ~LineWatcher() {} 186 187 protected: 188 /** 189 * OnError will be called when |read| returns error. Derived class should 190 * implement this function to handle error cases when needed. 191 */ OnError()192 virtual void OnError() {} 193 virtual void OnLineRead(int aFd, nsDependentCSubstring& aMessage) = 0; OnFileCanWriteWithoutBlocking(int)194 virtual void OnFileCanWriteWithoutBlocking(int /* aFd */) override {} 195 196 private: 197 void OnFileCanReadWithoutBlocking(int aFd) final; 198 199 mozilla::UniquePtr<char[]> mReceiveBuffer; 200 int mReceivedIndex; 201 int mBufferSize; 202 char mTerminator; 203 }; 204 } // namespace base 205 206 #endif // BASE_MESSAGE_PUMP_LIBEVENT_H_ 207