1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 
7 #ifndef BASE_MESSAGE_PUMP_LIBEVENT_H_
8 #define BASE_MESSAGE_PUMP_LIBEVENT_H_
9 
10 #include "base/message_pump.h"
11 #include "base/time.h"
12 #include "mozilla/UniquePtr.h"
13 #include "nsStringFwd.h"
14 
15 // Declare structs we need from libevent.h rather than including it
16 struct event_base;
17 struct event;
18 
19 namespace base {
20 
21 // Class to monitor sockets and issue callbacks when sockets are ready for I/O
22 // TODO(dkegel): add support for background file IO somehow
23 class MessagePumpLibevent : public MessagePump {
24  public:
25   // Object returned by WatchFileDescriptor to manage further watching.
26   class FileDescriptorWatcher {
27    public:
28     FileDescriptorWatcher();
29     ~FileDescriptorWatcher();  // Implicitly calls StopWatchingFileDescriptor.
30 
31     // NOTE: These methods aren't called StartWatching()/StopWatching() to
32     // avoid confusion with the win32 ObjectWatcher class.
33 
34     // Stop watching the FD, always safe to call.  No-op if there's nothing
35     // to do.
36     bool StopWatchingFileDescriptor();
37 
38    private:
39     // Called by MessagePumpLibevent, ownership of |e| is transferred to this
40     // object.
41     void Init(event* e, bool is_persistent);
42 
43     // Used by MessagePumpLibevent to take ownership of event_.
44     event* ReleaseEvent();
45     friend class MessagePumpLibevent;
46 
47    private:
48     bool is_persistent_;  // false if this event is one-shot.
49     event* event_;
50     DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
51   };
52 
53   // Used with WatchFileDescptor to asynchronously monitor the I/O readiness of
54   // a File Descriptor.
55   class Watcher {
56    public:
~Watcher()57     virtual ~Watcher() {}
58     // Called from MessageLoop::Run when an FD can be read from/written to
59     // without blocking
60     virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
61     virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
62   };
63 
64   MessagePumpLibevent();
65 
66   enum Mode {
67     WATCH_READ = 1 << 0,
68     WATCH_WRITE = 1 << 1,
69     WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
70   };
71 
72   // Have the current thread's message loop watch for a a situation in which
73   // reading/writing to the FD can be performed without Blocking.
74   // Callers must provide a preallocated FileDescriptorWatcher object which
75   // can later be used to manage the Lifetime of this event.
76   // If a FileDescriptorWatcher is passed in which is already attached to
77   // an event, then the effect is cumulative i.e. after the call |controller|
78   // will watch both the previous event and the new one.
79   // If an error occurs while calling this method in a cumulative fashion, the
80   // event previously attached to |controller| is aborted.
81   // Returns true on success.
82   // TODO(dkegel): switch to edge-triggered readiness notification
83   bool WatchFileDescriptor(int fd, bool persistent, Mode mode,
84                            FileDescriptorWatcher* controller,
85                            Watcher* delegate);
86 
87   // This is analagous to FileDescriptorWatcher above, which really is
88   // just a wrapper around libevent's |struct event|.  This class acts
89   // as a sort of "scoped event watcher" in that it guarantees that
90   // when this class is out of scope, the signal-event it wraps is
91   // removed from libevent's guts.
92   //
93   // XXX/cjones: this isn't my favorite API, but preserving it in
94   // order to match code above
95   class SignalEvent {
96     friend class MessagePumpLibevent;
97 
98    public:
99     SignalEvent();
100     ~SignalEvent();  // implicitly calls StopCatching()
101 
102     // Have libevent forget this event.
103     bool StopCatching();
104 
105    private:
106     void Init(event* e);
107     event* ReleaseEvent();
108 
109     event* event_;
110 
111     DISALLOW_COPY_AND_ASSIGN(SignalEvent);
112   };
113 
114   class SignalWatcher {
115    public:
~SignalWatcher()116     virtual ~SignalWatcher() {}
117     // Called from MessageLoop::Run when |sig| has been delivered to
118     // this process
119     virtual void OnSignal(int sig) = 0;
120   };
121 
122   // Have the current thread's message loop catch the signal |sig|.
123   // Multiple watchers can catch the same signal; they're all notified
124   // upon its delivery.  Callers must provide a preallocated
125   // SignalEvent object which can be used to manage the lifetime of
126   // this event.  Returns true on success.
127   bool CatchSignal(int sig, SignalEvent* sigevent, SignalWatcher* delegate);
128 
129   // MessagePump methods:
130   virtual void Run(Delegate* delegate) override;
131   virtual void Quit() override;
132   virtual void ScheduleWork() override;
133   virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
134 
135  protected:
136   virtual ~MessagePumpLibevent();
137 
138  private:
139   // Risky part of constructor.  Returns true on success.
140   bool Init();
141 
142   // This flag is set to false when Run should return.
143   bool keep_running_;
144 
145   // This flag is set when inside Run.
146   bool in_run_;
147 
148   // The time at which we should call DoDelayedWork.
149   TimeTicks delayed_work_time_;
150 
151   // Libevent dispatcher.  Watches all sockets registered with it, and sends
152   // readiness callbacks when a socket is ready for I/O.
153   event_base* event_base_;
154 
155   // Called by libevent to tell us a registered FD can be read/written to.
156   static void OnLibeventNotification(int fd, short flags, void* context);
157 
158   // Called by libevent upon receiving a signal
159   static void OnLibeventSignalNotification(int sig, short flags, void* context);
160 
161   // Unix pipe used to implement ScheduleWork()
162   // ... callback; called by libevent inside Run() when pipe is ready to read
163   static void OnWakeup(int socket, short flags, void* context);
164   // ... write end; ScheduleWork() writes a single byte to it
165   int wakeup_pipe_in_;
166   // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
167   int wakeup_pipe_out_;
168   // ... libevent wrapper for read end
169   event* wakeup_event_;
170 
171   DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
172 };
173 
174 /**
175  *  LineWatcher overrides OnFileCanReadWithoutBlocking. It separates the read
176  *  data by mTerminator and passes each line to OnLineRead.
177  */
178 class LineWatcher : public MessagePumpLibevent::Watcher {
179  public:
LineWatcher(char aTerminator,int aBufferSize)180   LineWatcher(char aTerminator, int aBufferSize)
181       : mReceivedIndex(0), mBufferSize(aBufferSize), mTerminator(aTerminator) {
182     mReceiveBuffer = mozilla::MakeUnique<char[]>(mBufferSize);
183   }
184 
~LineWatcher()185   ~LineWatcher() {}
186 
187  protected:
188   /**
189    * OnError will be called when |read| returns error. Derived class should
190    * implement this function to handle error cases when needed.
191    */
OnError()192   virtual void OnError() {}
193   virtual void OnLineRead(int aFd, nsDependentCSubstring& aMessage) = 0;
OnFileCanWriteWithoutBlocking(int)194   virtual void OnFileCanWriteWithoutBlocking(int /* aFd */) override {}
195 
196  private:
197   void OnFileCanReadWithoutBlocking(int aFd) final;
198 
199   mozilla::UniquePtr<char[]> mReceiveBuffer;
200   int mReceivedIndex;
201   int mBufferSize;
202   char mTerminator;
203 };
204 }  // namespace base
205 
206 #endif  // BASE_MESSAGE_PUMP_LIBEVENT_H_
207