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