1 : // Copyright (c) 2008 The Chromium Authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "base/message_pump_libevent.h"
6 :
7 : #include <errno.h>
8 : #include <fcntl.h>
9 : #if defined(ANDROID) || defined(OS_POSIX)
10 : #include <unistd.h>
11 : #endif
12 :
13 : #include "eintr_wrapper.h"
14 : #include "base/logging.h"
15 : #include "base/scoped_nsautorelease_pool.h"
16 : #include "base/scoped_ptr.h"
17 : #include "base/time.h"
18 : #include "third_party/libevent/event.h"
19 :
20 : // Lifecycle of struct event
21 : // Libevent uses two main data structures:
22 : // struct event_base (of which there is one per message pump), and
23 : // struct event (of which there is roughly one per socket).
24 : // The socket's struct event is created in
25 : // MessagePumpLibevent::WatchFileDescriptor(),
26 : // is owned by the FileDescriptorWatcher, and is destroyed in
27 : // StopWatchingFileDescriptor().
28 : // It is moved into and out of lists in struct event_base by
29 : // the libevent functions event_add() and event_del().
30 : //
31 : // TODO(dkegel):
32 : // At the moment bad things happen if a FileDescriptorWatcher
33 : // is active after its MessagePumpLibevent has been destroyed.
34 : // See MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop
35 : // Not clear yet whether that situation occurs in practice,
36 : // but if it does, we need to fix it.
37 :
38 : namespace base {
39 :
40 : // Return 0 on success
41 : // Too small a function to bother putting in a library?
42 2840 : static int SetNonBlocking(int fd) {
43 2840 : int flags = fcntl(fd, F_GETFL, 0);
44 2840 : if (flags == -1)
45 0 : flags = 0;
46 2840 : return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
47 : }
48 :
49 3 : MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
50 : : is_persistent_(false),
51 3 : event_(NULL) {
52 3 : }
53 :
54 0 : MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
55 0 : if (event_) {
56 0 : StopWatchingFileDescriptor();
57 : }
58 0 : }
59 :
60 0 : void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e,
61 : bool is_persistent) {
62 0 : DCHECK(e);
63 0 : DCHECK(event_ == NULL);
64 :
65 0 : is_persistent_ = is_persistent;
66 0 : event_ = e;
67 0 : }
68 :
69 0 : event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
70 0 : struct event *e = event_;
71 0 : event_ = NULL;
72 0 : return e;
73 : }
74 :
75 0 : bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
76 0 : event* e = ReleaseEvent();
77 0 : if (e == NULL)
78 0 : return true;
79 :
80 : // event_del() is a no-op if the event isn't active.
81 0 : int rv = event_del(e);
82 : delete e;
83 0 : return (rv == 0);
84 : }
85 :
86 : // Called if a byte is received on the wakeup pipe.
87 1419 : void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
88 : base::MessagePumpLibevent* that =
89 1419 : static_cast<base::MessagePumpLibevent*>(context);
90 1419 : DCHECK(that->wakeup_pipe_out_ == socket);
91 :
92 : // Remove and discard the wakeup byte.
93 : char buf;
94 1419 : int nread = HANDLE_EINTR(read(socket, &buf, 1));
95 1419 : DCHECK_EQ(nread, 1);
96 : // Tell libevent to break out of inner loop.
97 1419 : event_base_loopbreak(that->event_base_);
98 1419 : }
99 :
100 1420 : MessagePumpLibevent::MessagePumpLibevent()
101 : : keep_running_(true),
102 : in_run_(false),
103 1420 : event_base_(event_base_new()),
104 : wakeup_pipe_in_(-1),
105 2840 : wakeup_pipe_out_(-1) {
106 1420 : if (!Init())
107 0 : NOTREACHED();
108 1420 : }
109 :
110 1420 : bool MessagePumpLibevent::Init() {
111 : int fds[2];
112 1420 : if (pipe(fds)) {
113 0 : DLOG(ERROR) << "pipe() failed, errno: " << errno;
114 0 : return false;
115 : }
116 1420 : if (SetNonBlocking(fds[0])) {
117 0 : DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
118 0 : return false;
119 : }
120 1420 : if (SetNonBlocking(fds[1])) {
121 0 : DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
122 0 : return false;
123 : }
124 1420 : wakeup_pipe_out_ = fds[0];
125 1420 : wakeup_pipe_in_ = fds[1];
126 :
127 1420 : wakeup_event_ = new event;
128 : event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
129 1420 : OnWakeup, this);
130 1420 : event_base_set(event_base_, wakeup_event_);
131 :
132 1420 : if (event_add(wakeup_event_, 0))
133 0 : return false;
134 1420 : return true;
135 : }
136 :
137 4257 : MessagePumpLibevent::~MessagePumpLibevent() {
138 1419 : DCHECK(wakeup_event_);
139 1419 : DCHECK(event_base_);
140 1419 : event_del(wakeup_event_);
141 1419 : delete wakeup_event_;
142 1419 : if (wakeup_pipe_in_ >= 0)
143 1419 : close(wakeup_pipe_in_);
144 1419 : if (wakeup_pipe_out_ >= 0)
145 1419 : close(wakeup_pipe_out_);
146 1419 : event_base_free(event_base_);
147 5676 : }
148 :
149 0 : bool MessagePumpLibevent::WatchFileDescriptor(int fd,
150 : bool persistent,
151 : Mode mode,
152 : FileDescriptorWatcher *controller,
153 : Watcher *delegate) {
154 0 : DCHECK(fd > 0);
155 0 : DCHECK(controller);
156 0 : DCHECK(delegate);
157 0 : DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
158 :
159 0 : int event_mask = persistent ? EV_PERSIST : 0;
160 0 : if ((mode & WATCH_READ) != 0) {
161 0 : event_mask |= EV_READ;
162 : }
163 0 : if ((mode & WATCH_WRITE) != 0) {
164 0 : event_mask |= EV_WRITE;
165 : }
166 :
167 : // |should_delete_event| is true if we're modifying an event that's currently
168 : // active in |controller|.
169 : // If we're modifying an existing event and there's an error then we need to
170 : // tell libevent to clean it up via event_delete() before returning.
171 0 : bool should_delete_event = true;
172 0 : scoped_ptr<event> evt(controller->ReleaseEvent());
173 0 : if (evt.get() == NULL) {
174 0 : should_delete_event = false;
175 : // Ownership is transferred to the controller.
176 0 : evt.reset(new event);
177 : }
178 :
179 : // Set current interest mask and message pump for this event.
180 : event_set(evt.get(), fd, event_mask, OnLibeventNotification,
181 0 : delegate);
182 :
183 : // Tell libevent which message pump this socket will belong to when we add it.
184 0 : if (event_base_set(event_base_, evt.get()) != 0) {
185 0 : if (should_delete_event) {
186 0 : event_del(evt.get());
187 : }
188 0 : return false;
189 : }
190 :
191 : // Add this socket to the list of monitored sockets.
192 0 : if (event_add(evt.get(), NULL) != 0) {
193 0 : if (should_delete_event) {
194 0 : event_del(evt.get());
195 : }
196 0 : return false;
197 : }
198 :
199 : // Transfer ownership of evt to controller.
200 0 : controller->Init(evt.release(), persistent);
201 0 : return true;
202 : }
203 :
204 :
205 0 : void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
206 : void* context) {
207 0 : Watcher* watcher = static_cast<Watcher*>(context);
208 :
209 0 : if (flags & EV_WRITE) {
210 0 : watcher->OnFileCanWriteWithoutBlocking(fd);
211 : }
212 0 : if (flags & EV_READ) {
213 0 : watcher->OnFileCanReadWithoutBlocking(fd);
214 : }
215 0 : }
216 :
217 :
218 0 : MessagePumpLibevent::SignalEvent::SignalEvent() :
219 0 : event_(NULL)
220 : {
221 0 : }
222 :
223 0 : MessagePumpLibevent::SignalEvent::~SignalEvent()
224 : {
225 0 : if (event_) {
226 0 : StopCatching();
227 : }
228 0 : }
229 :
230 : void
231 0 : MessagePumpLibevent::SignalEvent::Init(event *e)
232 : {
233 0 : DCHECK(e);
234 0 : DCHECK(event_ == NULL);
235 0 : event_ = e;
236 0 : }
237 :
238 : bool
239 0 : MessagePumpLibevent::SignalEvent::StopCatching()
240 : {
241 : // XXX/cjones: this code could be shared with
242 : // FileDescriptorWatcher. ironic that libevent is "more"
243 : // object-oriented than this C++
244 0 : event* e = ReleaseEvent();
245 0 : if (e == NULL)
246 0 : return true;
247 :
248 : // event_del() is a no-op if the event isn't active.
249 0 : int rv = event_del(e);
250 : delete e;
251 0 : return (rv == 0);
252 : }
253 :
254 : event *
255 0 : MessagePumpLibevent::SignalEvent::ReleaseEvent()
256 : {
257 0 : event *e = event_;
258 0 : event_ = NULL;
259 0 : return e;
260 : }
261 :
262 : bool
263 0 : MessagePumpLibevent::CatchSignal(int sig,
264 : SignalEvent* sigevent,
265 : SignalWatcher* delegate)
266 : {
267 0 : DCHECK(sig > 0);
268 0 : DCHECK(sigevent);
269 0 : DCHECK(delegate);
270 : // TODO if we want to support re-using SignalEvents, this code needs
271 : // to jump through the same hoops as WatchFileDescriptor(). Not
272 : // needed at present
273 0 : DCHECK(NULL == sigevent->event_);
274 :
275 0 : scoped_ptr<event> evt(new event);
276 0 : signal_set(evt.get(), sig, OnLibeventSignalNotification, delegate);
277 :
278 0 : if (event_base_set(event_base_, evt.get()))
279 0 : return false;
280 :
281 0 : if (signal_add(evt.get(), NULL))
282 0 : return false;
283 :
284 : // Transfer ownership of evt to controller.
285 0 : sigevent->Init(evt.release());
286 0 : return true;
287 : }
288 :
289 : void
290 0 : MessagePumpLibevent::OnLibeventSignalNotification(int sig, short flags,
291 : void* context)
292 : {
293 0 : DCHECK(sig > 0);
294 0 : DCHECK(EV_SIGNAL == flags);
295 0 : DCHECK(context);
296 0 : reinterpret_cast<SignalWatcher*>(context)->OnSignal(sig);
297 0 : }
298 :
299 :
300 : // Reentrant!
301 1420 : void MessagePumpLibevent::Run(Delegate* delegate) {
302 1420 : DCHECK(keep_running_) << "Quit must have been called outside of Run!";
303 :
304 1420 : bool old_in_run = in_run_;
305 1420 : in_run_ = true;
306 :
307 2838 : for (;;) {
308 4258 : ScopedNSAutoreleasePool autorelease_pool;
309 :
310 4258 : bool did_work = delegate->DoWork();
311 4258 : if (!keep_running_)
312 0 : break;
313 :
314 4258 : did_work |= delegate->DoDelayedWork(&delayed_work_time_);
315 4258 : if (!keep_running_)
316 0 : break;
317 :
318 4258 : if (did_work)
319 1419 : continue;
320 :
321 2839 : did_work = delegate->DoIdleWork();
322 2839 : if (!keep_running_)
323 1419 : break;
324 :
325 1420 : if (did_work)
326 0 : continue;
327 :
328 : // EVLOOP_ONCE tells libevent to only block once,
329 : // but to service all pending events when it wakes up.
330 1420 : if (delayed_work_time_.is_null()) {
331 1420 : event_base_loop(event_base_, EVLOOP_ONCE);
332 : } else {
333 0 : TimeDelta delay = delayed_work_time_ - Time::Now();
334 0 : if (delay > TimeDelta()) {
335 : struct timeval poll_tv;
336 0 : poll_tv.tv_sec = delay.InSeconds();
337 0 : poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
338 0 : event_base_loopexit(event_base_, &poll_tv);
339 0 : event_base_loop(event_base_, EVLOOP_ONCE);
340 : } else {
341 : // It looks like delayed_work_time_ indicates a time in the past, so we
342 : // need to call DoDelayedWork now.
343 0 : delayed_work_time_ = Time();
344 : }
345 : }
346 : }
347 :
348 1419 : keep_running_ = true;
349 1419 : in_run_ = old_in_run;
350 1419 : }
351 :
352 1419 : void MessagePumpLibevent::Quit() {
353 1419 : DCHECK(in_run_);
354 : // Tell both libevent and Run that they should break out of their loops.
355 1419 : keep_running_ = false;
356 1419 : ScheduleWork();
357 1419 : }
358 :
359 2838 : void MessagePumpLibevent::ScheduleWork() {
360 : // Tell libevent (in a threadsafe way) that it should break out of its loop.
361 2838 : char buf = 0;
362 2838 : int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1));
363 2838 : DCHECK(nwrite == 1 || errno == EAGAIN)
364 0 : << "[nwrite:" << nwrite << "] [errno:" << errno << "]";
365 2838 : }
366 :
367 0 : void MessagePumpLibevent::ScheduleDelayedWork(const Time& delayed_work_time) {
368 : // We know that we can't be blocked on Wait right now since this method can
369 : // only be called on the same thread as Run, so we only need to update our
370 : // record of how long to sleep when we do sleep.
371 0 : delayed_work_time_ = delayed_work_time;
372 0 : }
373 :
374 : } // namespace base
|