blob: ff0d40d3c439c521a0a69f63c5d875c4074346be [file] [log] [blame]
[email protected]3b63f8f42011-03-28 01:54:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]36987e92008-09-18 18:46:262// 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
[email protected]91cb3702009-01-20 21:12:157#include <errno.h>
[email protected]157fd8522009-01-20 22:12:268#include <fcntl.h>
[email protected]89836e22008-09-25 20:33:429
[email protected]5be7da242009-11-20 23:16:2610#include "base/auto_reset.h"
[email protected]8d5f3ac2011-07-20 16:01:3211#include "base/compiler_specific.h"
[email protected]9cfb89a2010-06-09 21:20:4112#include "base/eintr_wrapper.h"
[email protected]36987e92008-09-18 18:46:2613#include "base/logging.h"
[email protected]29535ff2011-12-06 15:09:5614#if defined(OS_MACOSX)
15#include "base/mac/scoped_nsautorelease_pool.h"
16#endif
[email protected]3b63f8f42011-03-28 01:54:1517#include "base/memory/scoped_ptr.h"
[email protected]9cfb89a2010-06-09 21:20:4118#include "base/observer_list.h"
[email protected]36987e92008-09-18 18:46:2619#include "base/time.h"
[email protected]e97831d2010-01-07 18:16:5820#if defined(USE_SYSTEM_LIBEVENT)
21#include <event.h>
22#else
[email protected]36987e92008-09-18 18:46:2623#include "third_party/libevent/event.h"
[email protected]e97831d2010-01-07 18:16:5824#endif
[email protected]36987e92008-09-18 18:46:2625
[email protected]badf5cf2011-10-29 03:44:4426#if defined(OS_MACOSX)
27#include "base/mac/scoped_nsautorelease_pool.h"
28#endif
29
[email protected]f74c8962009-04-22 20:01:3630// Lifecycle of struct event
31// Libevent uses two main data structures:
32// struct event_base (of which there is one per message pump), and
33// struct event (of which there is roughly one per socket).
34// The socket's struct event is created in
35// MessagePumpLibevent::WatchFileDescriptor(),
36// is owned by the FileDescriptorWatcher, and is destroyed in
37// StopWatchingFileDescriptor().
38// It is moved into and out of lists in struct event_base by
39// the libevent functions event_add() and event_del().
40//
41// TODO(dkegel):
42// At the moment bad things happen if a FileDescriptorWatcher
43// is active after its MessagePumpLibevent has been destroyed.
44// See MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop
45// Not clear yet whether that situation occurs in practice,
46// but if it does, we need to fix it.
47
[email protected]36987e92008-09-18 18:46:2648namespace base {
49
50// Return 0 on success
51// Too small a function to bother putting in a library?
[email protected]e45e6c02008-12-15 22:02:1752static int SetNonBlocking(int fd) {
53 int flags = fcntl(fd, F_GETFL, 0);
54 if (flags == -1)
55 flags = 0;
56 return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
57}
58
59MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
60 : is_persistent_(false),
[email protected]9cfb89a2010-06-09 21:20:4161 event_(NULL),
62 pump_(NULL),
[email protected]e4d70962011-07-21 20:16:1163 watcher_(NULL),
[email protected]8d5f3ac2011-07-20 16:01:3264 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
[email protected]e45e6c02008-12-15 22:02:1765}
66
67MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
[email protected]f74c8962009-04-22 20:01:3668 if (event_) {
[email protected]e45e6c02008-12-15 22:02:1769 StopWatchingFileDescriptor();
70 }
71}
72
[email protected]eae9c062011-01-11 00:50:5973bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
74 event* e = ReleaseEvent();
75 if (e == NULL)
76 return true;
77
78 // event_del() is a no-op if the event isn't active.
79 int rv = event_del(e);
80 delete e;
81 pump_ = NULL;
82 watcher_ = NULL;
83 return (rv == 0);
84}
85
[email protected]e45e6c02008-12-15 22:02:1786void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e,
87 bool is_persistent) {
88 DCHECK(e);
[email protected]5d2b4492011-03-01 02:48:0589 DCHECK(!event_);
[email protected]e45e6c02008-12-15 22:02:1790
91 is_persistent_ = is_persistent;
[email protected]f74c8962009-04-22 20:01:3692 event_ = e;
[email protected]e45e6c02008-12-15 22:02:1793}
94
95event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
[email protected]f74c8962009-04-22 20:01:3696 struct event *e = event_;
97 event_ = NULL;
98 return e;
[email protected]e45e6c02008-12-15 22:02:1799}
100
[email protected]9cfb89a2010-06-09 21:20:41101void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
102 int fd, MessagePumpLibevent* pump) {
[email protected]8d5f3ac2011-07-20 16:01:32103 // Since OnFileCanWriteWithoutBlocking() gets called first, it can stop
104 // watching the file descriptor.
105 if (!watcher_)
106 return;
[email protected]9cfb89a2010-06-09 21:20:41107 pump->WillProcessIOEvent();
108 watcher_->OnFileCanReadWithoutBlocking(fd);
109 pump->DidProcessIOEvent();
110}
111
112void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
113 int fd, MessagePumpLibevent* pump) {
[email protected]8d5f3ac2011-07-20 16:01:32114 DCHECK(watcher_);
[email protected]9cfb89a2010-06-09 21:20:41115 pump->WillProcessIOEvent();
116 watcher_->OnFileCanWriteWithoutBlocking(fd);
117 pump->DidProcessIOEvent();
118}
119
[email protected]36987e92008-09-18 18:46:26120MessagePumpLibevent::MessagePumpLibevent()
121 : keep_running_(true),
122 in_run_(false),
[email protected]4b4a94f22b2011-07-01 01:55:29123 processed_io_events_(false),
[email protected]36987e92008-09-18 18:46:26124 event_base_(event_base_new()),
125 wakeup_pipe_in_(-1),
126 wakeup_pipe_out_(-1) {
127 if (!Init())
128 NOTREACHED();
129}
130
[email protected]36987e92008-09-18 18:46:26131MessagePumpLibevent::~MessagePumpLibevent() {
132 DCHECK(wakeup_event_);
133 DCHECK(event_base_);
134 event_del(wakeup_event_);
135 delete wakeup_event_;
[email protected]70eb6572010-06-23 00:37:46136 if (wakeup_pipe_in_ >= 0) {
137 if (HANDLE_EINTR(close(wakeup_pipe_in_)) < 0)
[email protected]a42d4632011-10-26 21:48:00138 DPLOG(ERROR) << "close";
[email protected]70eb6572010-06-23 00:37:46139 }
140 if (wakeup_pipe_out_ >= 0) {
141 if (HANDLE_EINTR(close(wakeup_pipe_out_)) < 0)
[email protected]a42d4632011-10-26 21:48:00142 DPLOG(ERROR) << "close";
[email protected]70eb6572010-06-23 00:37:46143 }
[email protected]36987e92008-09-18 18:46:26144 event_base_free(event_base_);
145}
146
[email protected]e45e6c02008-12-15 22:02:17147bool MessagePumpLibevent::WatchFileDescriptor(int fd,
148 bool persistent,
149 Mode mode,
150 FileDescriptorWatcher *controller,
151 Watcher *delegate) {
[email protected]5dcd8652009-12-03 21:38:51152 DCHECK_GE(fd, 0);
[email protected]e45e6c02008-12-15 22:02:17153 DCHECK(controller);
154 DCHECK(delegate);
155 DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
[email protected]b4339c3a2011-05-13 16:19:23156 // WatchFileDescriptor should be called on the pump thread. It is not
157 // threadsafe, and your watcher may never be registered.
158 DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread());
[email protected]36987e92008-09-18 18:46:26159
[email protected]e45e6c02008-12-15 22:02:17160 int event_mask = persistent ? EV_PERSIST : 0;
161 if ((mode & WATCH_READ) != 0) {
162 event_mask |= EV_READ;
163 }
164 if ((mode & WATCH_WRITE) != 0) {
165 event_mask |= EV_WRITE;
[email protected]900342a2008-12-12 19:55:17166 }
[email protected]36987e92008-09-18 18:46:26167
[email protected]e45e6c02008-12-15 22:02:17168 scoped_ptr<event> evt(controller->ReleaseEvent());
169 if (evt.get() == NULL) {
[email protected]e45e6c02008-12-15 22:02:17170 // Ownership is transferred to the controller.
171 evt.reset(new event);
[email protected]052fd452009-09-23 17:56:25172 } else {
[email protected]052fd452009-09-23 17:56:25173 // Make sure we don't pick up any funky internal libevent masks.
174 int old_interest_mask = evt.get()->ev_events &
175 (EV_READ | EV_WRITE | EV_PERSIST);
176
177 // Combine old/new event masks.
178 event_mask |= old_interest_mask;
179
180 // Must disarm the event before we can reuse it.
181 event_del(evt.get());
[email protected]cee22a92009-09-24 19:45:55182
183 // It's illegal to use this function to listen on 2 separate fds with the
184 // same |controller|.
185 if (EVENT_FD(evt.get()) != fd) {
186 NOTREACHED() << "FDs don't match" << EVENT_FD(evt.get()) << "!=" << fd;
187 return false;
188 }
[email protected]e45e6c02008-12-15 22:02:17189 }
[email protected]900342a2008-12-12 19:55:17190
[email protected]e45e6c02008-12-15 22:02:17191 // Set current interest mask and message pump for this event.
[email protected]9cfb89a2010-06-09 21:20:41192 event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller);
[email protected]e45e6c02008-12-15 22:02:17193
194 // Tell libevent which message pump this socket will belong to when we add it.
195 if (event_base_set(event_base_, evt.get()) != 0) {
[email protected]e45e6c02008-12-15 22:02:17196 return false;
197 }
198
199 // Add this socket to the list of monitored sockets.
200 if (event_add(evt.get(), NULL) != 0) {
[email protected]e45e6c02008-12-15 22:02:17201 return false;
202 }
203
[email protected]f74c8962009-04-22 20:01:36204 // Transfer ownership of evt to controller.
[email protected]e45e6c02008-12-15 22:02:17205 controller->Init(evt.release(), persistent);
[email protected]9cfb89a2010-06-09 21:20:41206
207 controller->set_watcher(delegate);
208 controller->set_pump(this);
209
[email protected]e45e6c02008-12-15 22:02:17210 return true;
[email protected]900342a2008-12-12 19:55:17211}
212
[email protected]eae9c062011-01-11 00:50:59213void MessagePumpLibevent::AddIOObserver(IOObserver *obs) {
214 io_observers_.AddObserver(obs);
215}
[email protected]9cfb89a2010-06-09 21:20:41216
[email protected]eae9c062011-01-11 00:50:59217void MessagePumpLibevent::RemoveIOObserver(IOObserver *obs) {
218 io_observers_.RemoveObserver(obs);
[email protected]1d2eb132008-12-08 17:36:06219}
220
[email protected]ba92eb12009-11-06 21:53:52221// Tell libevent to break out of inner loop.
222static void timer_callback(int fd, short events, void *context)
223{
224 event_base_loopbreak((struct event_base *)context);
225}
226
[email protected]36987e92008-09-18 18:46:26227// Reentrant!
228void MessagePumpLibevent::Run(Delegate* delegate) {
229 DCHECK(keep_running_) << "Quit must have been called outside of Run!";
[email protected]0fbd70332010-06-01 19:28:34230 AutoReset<bool> auto_reset_in_run(&in_run_, true);
[email protected]36987e92008-09-18 18:46:26231
[email protected]ba92eb12009-11-06 21:53:52232 // event_base_loopexit() + EVLOOP_ONCE is leaky, see http://crbug.com/25641.
233 // Instead, make our own timer and reuse it on each call to event_base_loop().
234 scoped_ptr<event> timer_event(new event);
235
[email protected]36987e92008-09-18 18:46:26236 for (;;) {
[email protected]badf5cf2011-10-29 03:44:44237#if defined(OS_MACOSX)
[email protected]c2818d42010-10-18 02:47:39238 mac::ScopedNSAutoreleasePool autorelease_pool;
[email protected]badf5cf2011-10-29 03:44:44239#endif
[email protected]89836e22008-09-25 20:33:42240
[email protected]36987e92008-09-18 18:46:26241 bool did_work = delegate->DoWork();
242 if (!keep_running_)
243 break;
244
[email protected]4b4a94f22b2011-07-01 01:55:29245 event_base_loop(event_base_, EVLOOP_NONBLOCK);
246 did_work |= processed_io_events_;
247 processed_io_events_ = false;
248 if (!keep_running_)
249 break;
250
[email protected]36987e92008-09-18 18:46:26251 did_work |= delegate->DoDelayedWork(&delayed_work_time_);
252 if (!keep_running_)
253 break;
254
255 if (did_work)
256 continue;
257
258 did_work = delegate->DoIdleWork();
259 if (!keep_running_)
260 break;
261
262 if (did_work)
263 continue;
264
265 // EVLOOP_ONCE tells libevent to only block once,
266 // but to service all pending events when it wakes up.
267 if (delayed_work_time_.is_null()) {
268 event_base_loop(event_base_, EVLOOP_ONCE);
269 } else {
[email protected]7e7fab42010-11-06 22:23:29270 TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
[email protected]36987e92008-09-18 18:46:26271 if (delay > TimeDelta()) {
272 struct timeval poll_tv;
273 poll_tv.tv_sec = delay.InSeconds();
274 poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
[email protected]ba92eb12009-11-06 21:53:52275 event_set(timer_event.get(), -1, 0, timer_callback, event_base_);
276 event_base_set(event_base_, timer_event.get());
277 event_add(timer_event.get(), &poll_tv);
[email protected]36987e92008-09-18 18:46:26278 event_base_loop(event_base_, EVLOOP_ONCE);
[email protected]ba92eb12009-11-06 21:53:52279 event_del(timer_event.get());
[email protected]36987e92008-09-18 18:46:26280 } else {
281 // It looks like delayed_work_time_ indicates a time in the past, so we
282 // need to call DoDelayedWork now.
[email protected]7e7fab42010-11-06 22:23:29283 delayed_work_time_ = TimeTicks();
[email protected]36987e92008-09-18 18:46:26284 }
285 }
286 }
287
288 keep_running_ = true;
[email protected]36987e92008-09-18 18:46:26289}
290
291void MessagePumpLibevent::Quit() {
292 DCHECK(in_run_);
293 // Tell both libevent and Run that they should break out of their loops.
294 keep_running_ = false;
295 ScheduleWork();
296}
297
298void MessagePumpLibevent::ScheduleWork() {
299 // Tell libevent (in a threadsafe way) that it should break out of its loop.
300 char buf = 0;
[email protected]157c61b2009-05-01 21:37:31301 int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1));
[email protected]3fae2282009-03-17 22:26:06302 DCHECK(nwrite == 1 || errno == EAGAIN)
303 << "[nwrite:" << nwrite << "] [errno:" << errno << "]";
[email protected]36987e92008-09-18 18:46:26304}
305
[email protected]7e7fab42010-11-06 22:23:29306void MessagePumpLibevent::ScheduleDelayedWork(
307 const TimeTicks& delayed_work_time) {
[email protected]36987e92008-09-18 18:46:26308 // We know that we can't be blocked on Wait right now since this method can
309 // only be called on the same thread as Run, so we only need to update our
310 // record of how long to sleep when we do sleep.
311 delayed_work_time_ = delayed_work_time;
312}
313
[email protected]9cfb89a2010-06-09 21:20:41314void MessagePumpLibevent::WillProcessIOEvent() {
315 FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
316}
317
318void MessagePumpLibevent::DidProcessIOEvent() {
319 FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
320}
321
[email protected]eae9c062011-01-11 00:50:59322bool MessagePumpLibevent::Init() {
323 int fds[2];
324 if (pipe(fds)) {
325 DLOG(ERROR) << "pipe() failed, errno: " << errno;
326 return false;
327 }
328 if (SetNonBlocking(fds[0])) {
329 DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
330 return false;
331 }
332 if (SetNonBlocking(fds[1])) {
333 DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
334 return false;
335 }
336 wakeup_pipe_out_ = fds[0];
337 wakeup_pipe_in_ = fds[1];
338
339 wakeup_event_ = new event;
340 event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
341 OnWakeup, this);
342 event_base_set(event_base_, wakeup_event_);
343
344 if (event_add(wakeup_event_, 0))
345 return false;
346 return true;
347}
348
349// static
350void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
351 void* context) {
[email protected]8d5f3ac2011-07-20 16:01:32352 base::WeakPtr<FileDescriptorWatcher> controller =
353 static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
354 DCHECK(controller.get());
[email protected]eae9c062011-01-11 00:50:59355
356 MessagePumpLibevent* pump = controller->pump();
[email protected]4b4a94f22b2011-07-01 01:55:29357 pump->processed_io_events_ = true;
[email protected]eae9c062011-01-11 00:50:59358
359 if (flags & EV_WRITE) {
360 controller->OnFileCanWriteWithoutBlocking(fd, pump);
361 }
[email protected]e4d70962011-07-21 20:16:11362 // Check |controller| in case it's been deleted in
363 // controller->OnFileCanWriteWithoutBlocking().
[email protected]8d5f3ac2011-07-20 16:01:32364 if (controller.get() && flags & EV_READ) {
[email protected]eae9c062011-01-11 00:50:59365 controller->OnFileCanReadWithoutBlocking(fd, pump);
366 }
367}
368
369// Called if a byte is received on the wakeup pipe.
370// static
371void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
372 base::MessagePumpLibevent* that =
373 static_cast<base::MessagePumpLibevent*>(context);
374 DCHECK(that->wakeup_pipe_out_ == socket);
375
376 // Remove and discard the wakeup byte.
377 char buf;
378 int nread = HANDLE_EINTR(read(socket, &buf, 1));
379 DCHECK_EQ(nread, 1);
[email protected]4b4a94f22b2011-07-01 01:55:29380 that->processed_io_events_ = true;
[email protected]eae9c062011-01-11 00:50:59381 // Tell libevent to break out of inner loop.
382 event_base_loopbreak(that->event_base_);
383}
384
[email protected]36987e92008-09-18 18:46:26385} // namespace base