| Index: base/message_pump_libevent.cc
|
| ===================================================================
|
| --- base/message_pump_libevent.cc (revision 0)
|
| +++ base/message_pump_libevent.cc (revision 0)
|
| @@ -0,0 +1,130 @@
|
| +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/message_pump_libevent.h"
|
| +#include "base/logging.h"
|
| +#include "base/time.h"
|
| +
|
| +#include "third_party/libevent/event.h"
|
| +
|
| +// Called if a byte is received on the wakeup pipe
|
| +extern "C" void MessagePumpLibevent_wakeup(int socket, short flags, void *context) {
|
| + base::MessagePumpLibevent* that = static_cast<base::MessagePumpLibevent*>(context);
|
| + DCHECK(that->wakeup_pipe_gazouta_ == socket);
|
| +
|
| + // remove and discard the wakeup byte
|
| + char buf;
|
| + int nread = read(socket, &buf, 1);
|
| + DCHECK(nread == 1);
|
| + // tell libevent to break out of inner loop
|
| + event_base_loopbreak(that->evbase_);
|
| +}
|
| +
|
| +namespace base {
|
| +
|
| +MessagePumpLibevent::MessagePumpLibevent()
|
| + : keep_running_(true) {
|
| + evbase_ = event_base_new();
|
| + wakeup_event_ = new event;
|
| +
|
| + // Dang, too much real work in the constructor.
|
| + int fds[2];
|
| + int err = pipe(fds);
|
| + DCHECK(!err);
|
| + if (err) {
|
| + wakeup_pipe_gazinta_ = -1;
|
| + wakeup_pipe_gazouta_ = -1;
|
| + memset(wakeup_event_, 0, sizeof(*wakeup_event_));
|
| + } else {
|
| + wakeup_pipe_gazouta_ = fds[0];
|
| + wakeup_pipe_gazinta_ = fds[1];
|
| + event_set(wakeup_event_, wakeup_pipe_gazouta_,
|
| + EV_READ | EV_PERSIST, MessagePumpLibevent_wakeup, this);
|
| + event_base_set(evbase_, wakeup_event_);
|
| +
|
| + if (event_add(wakeup_event_, 0) == -1) {
|
| + DCHECK(0);
|
| + // Did I mention this was too much real work in the constructor?
|
| + }
|
| + }
|
| +}
|
| +
|
| +MessagePumpLibevent::~MessagePumpLibevent() {
|
| + DCHECK(wakeup_event_);
|
| + DCHECK(evbase_);
|
| + event_del(wakeup_event_);
|
| + delete wakeup_event_;
|
| + wakeup_event_ = 0;
|
| + event_base_free(evbase_);
|
| + evbase_ = 0;
|
| +}
|
| +
|
| +void MessagePumpLibevent::Run(Delegate* delegate) {
|
| + DCHECK(keep_running_) << "Quit must have been called outside of Run!";
|
| +
|
| + for (;;) {
|
| + bool did_work = delegate->DoWork();
|
| + if (!keep_running_)
|
| + break;
|
| +
|
| + did_work |= delegate->DoDelayedWork(&delayed_work_time_);
|
| + if (!keep_running_)
|
| + break;
|
| +
|
| + if (did_work)
|
| + continue;
|
| +
|
| + did_work = delegate->DoIdleWork();
|
| + if (!keep_running_)
|
| + break;
|
| +
|
| + if (did_work)
|
| + continue;
|
| +
|
| + // 50 wakeups per second sucks, but without this, tests take a long time or hang.
|
| + int poll_ms = 20;
|
| + if (!delayed_work_time_.is_null()) {
|
| + TimeDelta delay = delayed_work_time_ - Time::Now();
|
| + if (delay > TimeDelta()) {
|
| + int delay_ms = delay.InMilliseconds();
|
| + if (delay_ms < poll_ms)
|
| + poll_ms = delay_ms;
|
| + } else {
|
| + // It looks like delayed_work_time_ indicates a time in the past, so we
|
| + // need to call DoDelayedWork now.
|
| + delayed_work_time_ = Time();
|
| + }
|
| + }
|
| + struct timeval poll_tv;
|
| + poll_tv.tv_sec = 0;
|
| + poll_tv.tv_usec = poll_ms * 1000;
|
| + event_base_loopexit(evbase_, &poll_tv);
|
| + event_base_loop(evbase_, 0);
|
| + }
|
| +
|
| + keep_running_ = true;
|
| +}
|
| +
|
| +void MessagePumpLibevent::Quit() {
|
| + ScheduleWork();
|
| + keep_running_ = false;
|
| +}
|
| +
|
| +void MessagePumpLibevent::ScheduleWork() {
|
| + // This can be called on any thread.
|
| + // Tell libevent (in a threadsafe way) that it should break out of its loop.
|
| + char buf = 0;
|
| + int nwrite = write(wakeup_pipe_gazinta_, &buf, 1);
|
| + DCHECK(nwrite == 1);
|
| +}
|
| +
|
| +void MessagePumpLibevent::ScheduleDelayedWork(const Time& delayed_work_time) {
|
| + // We know that we can't be blocked on Wait right now since this method can
|
| + // only be called on the same thread as Run, so we only need to update our
|
| + // record of how long to sleep when we do sleep.
|
| + delayed_work_time_ = delayed_work_time;
|
| +}
|
| +
|
| +} // namespace base
|
| +
|
|
|