LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - message_pump_libevent.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 189 72 38.1 %
Date: 2012-06-02 Functions: 24 10 41.7 %

       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

Generated by: LCOV version 1.7