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