summaryrefslogtreecommitdiff
path: root/ipc/chromium/src/base/message_pump_libevent.h
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/chromium/src/base/message_pump_libevent.h')
-rw-r--r--ipc/chromium/src/base/message_pump_libevent.h220
1 files changed, 220 insertions, 0 deletions
diff --git a/ipc/chromium/src/base/message_pump_libevent.h b/ipc/chromium/src/base/message_pump_libevent.h
new file mode 100644
index 0000000000..224f70932c
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_libevent.h
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+#ifndef BASE_MESSAGE_PUMP_LIBEVENT_H_
+#define BASE_MESSAGE_PUMP_LIBEVENT_H_
+
+#include "base/message_pump.h"
+#include "base/time.h"
+#include "mozilla/UniquePtr.h"
+
+// Declare structs we need from libevent.h rather than including it
+struct event_base;
+struct event;
+
+class nsDependentCSubstring;
+
+namespace base {
+
+// Class to monitor sockets and issue callbacks when sockets are ready for I/O
+// TODO(dkegel): add support for background file IO somehow
+class MessagePumpLibevent : public MessagePump {
+ public:
+
+ // Object returned by WatchFileDescriptor to manage further watching.
+ class FileDescriptorWatcher {
+ public:
+ FileDescriptorWatcher();
+ ~FileDescriptorWatcher(); // Implicitly calls StopWatchingFileDescriptor.
+
+ // NOTE: These methods aren't called StartWatching()/StopWatching() to
+ // avoid confusion with the win32 ObjectWatcher class.
+
+ // Stop watching the FD, always safe to call. No-op if there's nothing
+ // to do.
+ bool StopWatchingFileDescriptor();
+
+ private:
+ // Called by MessagePumpLibevent, ownership of |e| is transferred to this
+ // object.
+ void Init(event* e, bool is_persistent);
+
+ // Used by MessagePumpLibevent to take ownership of event_.
+ event *ReleaseEvent();
+ friend class MessagePumpLibevent;
+
+ private:
+ bool is_persistent_; // false if this event is one-shot.
+ event* event_;
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+ };
+
+ // Used with WatchFileDescptor to asynchronously monitor the I/O readiness of
+ // a File Descriptor.
+ class Watcher {
+ public:
+ virtual ~Watcher() {}
+ // Called from MessageLoop::Run when an FD can be read from/written to
+ // without blocking
+ virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
+ };
+
+ MessagePumpLibevent();
+
+ enum Mode {
+ WATCH_READ = 1 << 0,
+ WATCH_WRITE = 1 << 1,
+ WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+ };
+
+ // Have the current thread's message loop watch for a a situation in which
+ // reading/writing to the FD can be performed without Blocking.
+ // Callers must provide a preallocated FileDescriptorWatcher object which
+ // can later be used to manage the Lifetime of this event.
+ // If a FileDescriptorWatcher is passed in which is already attached to
+ // an event, then the effect is cumulative i.e. after the call |controller|
+ // will watch both the previous event and the new one.
+ // If an error occurs while calling this method in a cumulative fashion, the
+ // event previously attached to |controller| is aborted.
+ // Returns true on success.
+ // TODO(dkegel): switch to edge-triggered readiness notification
+ bool WatchFileDescriptor(int fd,
+ bool persistent,
+ Mode mode,
+ FileDescriptorWatcher *controller,
+ Watcher *delegate);
+
+
+ // This is analagous to FileDescriptorWatcher above, which really is
+ // just a wrapper around libevent's |struct event|. This class acts
+ // as a sort of "scoped event watcher" in that it guarantees that
+ // when this class is out of scope, the signal-event it wraps is
+ // removed from libevent's guts.
+ //
+ // XXX/cjones: this isn't my favorite API, but preserving it in
+ // order to match code above
+ class SignalEvent {
+ friend class MessagePumpLibevent;
+
+ public:
+ SignalEvent();
+ ~SignalEvent(); // implicitly calls StopCatching()
+
+ // Have libevent forget this event.
+ bool StopCatching();
+
+ private:
+ void Init(event* e);
+ event* ReleaseEvent();
+
+ event* event_;
+
+ DISALLOW_COPY_AND_ASSIGN(SignalEvent);
+ };
+
+ class SignalWatcher {
+ public:
+ virtual ~SignalWatcher() {}
+ // Called from MessageLoop::Run when |sig| has been delivered to
+ // this process
+ virtual void OnSignal(int sig) = 0;
+ };
+
+ // Have the current thread's message loop catch the signal |sig|.
+ // Multiple watchers can catch the same signal; they're all notified
+ // upon its delivery. Callers must provide a preallocated
+ // SignalEvent object which can be used to manage the lifetime of
+ // this event. Returns true on success.
+ bool CatchSignal(int sig,
+ SignalEvent* sigevent,
+ SignalWatcher* delegate);
+
+
+ // MessagePump methods:
+ virtual void Run(Delegate* delegate) override;
+ virtual void Quit() override;
+ virtual void ScheduleWork() override;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ protected:
+
+ virtual ~MessagePumpLibevent();
+
+ private:
+
+ // Risky part of constructor. Returns true on success.
+ bool Init();
+
+ // This flag is set to false when Run should return.
+ bool keep_running_;
+
+ // This flag is set when inside Run.
+ bool in_run_;
+
+ // The time at which we should call DoDelayedWork.
+ TimeTicks delayed_work_time_;
+
+ // Libevent dispatcher. Watches all sockets registered with it, and sends
+ // readiness callbacks when a socket is ready for I/O.
+ event_base* event_base_;
+
+ // Called by libevent to tell us a registered FD can be read/written to.
+ static void OnLibeventNotification(int fd, short flags,
+ void* context);
+
+ // Called by libevent upon receiving a signal
+ static void OnLibeventSignalNotification(int sig, short flags,
+ void* context);
+
+ // Unix pipe used to implement ScheduleWork()
+ // ... callback; called by libevent inside Run() when pipe is ready to read
+ static void OnWakeup(int socket, short flags, void* context);
+ // ... write end; ScheduleWork() writes a single byte to it
+ int wakeup_pipe_in_;
+ // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
+ int wakeup_pipe_out_;
+ // ... libevent wrapper for read end
+ event* wakeup_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
+};
+
+/**
+ * LineWatcher overrides OnFileCanReadWithoutBlocking. It separates the read
+ * data by mTerminator and passes each line to OnLineRead.
+ */
+class LineWatcher : public MessagePumpLibevent::Watcher
+{
+public:
+ LineWatcher(char aTerminator, int aBufferSize) : mReceivedIndex(0),
+ mBufferSize(aBufferSize),
+ mTerminator(aTerminator)
+ {
+ mReceiveBuffer = mozilla::MakeUnique<char[]>(mBufferSize);
+ }
+
+ ~LineWatcher() {}
+
+protected:
+ /**
+ * OnError will be called when |read| returns error. Derived class should
+ * implement this function to handle error cases when needed.
+ */
+ virtual void OnError() {}
+ virtual void OnLineRead(int aFd, nsDependentCSubstring& aMessage) = 0;
+ virtual void OnFileCanWriteWithoutBlocking(int /* aFd */) override {}
+private:
+ virtual void OnFileCanReadWithoutBlocking(int aFd) final override;
+
+ mozilla::UniquePtr<char[]> mReceiveBuffer;
+ int mReceivedIndex;
+ int mBufferSize;
+ char mTerminator;
+};
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_LIBEVENT_H_