• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
6 #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
7 
8 #include <glib.h>
9 #include <memory>
10 
11 #include "base/base_export.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/message_loop/message_pump.h"
14 #include "base/message_loop/watchable_io_message_pump_posix.h"
15 #include "base/threading/thread_checker.h"
16 #include "base/time/time.h"
17 
18 namespace base {
19 
20 // This class implements a base MessagePump needed for TYPE_UI MessageLoops on
21 // platforms using GLib.
22 class BASE_EXPORT MessagePumpGlib : public MessagePump,
23                                     public WatchableIOMessagePumpPosix {
24  public:
25   class FdWatchController : public FdWatchControllerInterface {
26    public:
27     explicit FdWatchController(const Location& from_here);
28 
29     FdWatchController(const FdWatchController&) = delete;
30     FdWatchController& operator=(const FdWatchController&) = delete;
31 
32     ~FdWatchController() override;
33 
34     // FdWatchControllerInterface:
35     bool StopWatchingFileDescriptor() override;
36 
37    private:
38     friend class MessagePumpGlib;
39     friend class MessagePumpGLibFdWatchTest;
40 
41     // FdWatchController instances can be reused (unless fd changes), so we
42     // need to keep track of initialization status and taking it into account
43     // when setting up a fd watching. Please refer to
44     // WatchableIOMessagePumpPosix docs for more details. This is called by
45     // WatchFileDescriptor() and sets up a GSource for the input parameters.
46     // The source is not attached here, so the events will not be fired until
47     // Attach() is called.
48     bool InitOrUpdate(int fd, int mode, FdWatcher* watcher);
49     // Returns the current initialization status.
50     bool IsInitialized() const;
51 
52     // Tries to attach the internal GSource instance to the |pump|'s
53     // GMainContext, so IO events start to be dispatched. Returns false if
54     // |this| is not correctly initialized, otherwise returns true.
55     bool Attach(MessagePumpGlib* pump);
56 
57     // Forward read and write events to |watcher_|. It is a no-op if watcher_
58     // is null, which can happen when controller is suddenly stopped through
59     // StopWatchingFileDescriptor().
60     void NotifyCanRead();
61     void NotifyCanWrite();
62 
63     raw_ptr<FdWatcher> watcher_ = nullptr;
64     raw_ptr<GSource> source_ = nullptr;
65     std::unique_ptr<GPollFD> poll_fd_;
66     // If this pointer is non-null, the pointee is set to true in the
67     // destructor.
68     raw_ptr<bool> was_destroyed_ = nullptr;
69   };
70 
71   MessagePumpGlib();
72 
73   MessagePumpGlib(const MessagePumpGlib&) = delete;
74   MessagePumpGlib& operator=(const MessagePumpGlib&) = delete;
75 
76   ~MessagePumpGlib() override;
77 
78   // Part of WatchableIOMessagePumpPosix interface.
79   // Please refer to WatchableIOMessagePumpPosix docs for more details.
80   bool WatchFileDescriptor(int fd,
81                            bool persistent,
82                            int mode,
83                            FdWatchController* controller,
84                            FdWatcher* delegate);
85 
86   // Internal methods used for processing the pump callbacks. They are public
87   // for simplicity but should not be used directly. HandlePrepare is called
88   // during the prepare step of glib, and returns a timeout that will be passed
89   // to the poll. HandleCheck is called after the poll has completed, and
90   // returns whether or not HandleDispatch should be called. HandleDispatch is
91   // called if HandleCheck returned true.
92   int HandlePrepare();
93   bool HandleCheck();
94   void HandleDispatch();
95 
96   // Very similar to the above, with the key difference that these functions are
97   // only used to track work items and never indicate work is available, and
98   // poll indefinitely.
99   void HandleObserverPrepare();
100   bool HandleObserverCheck();
101 
102   // Overridden from MessagePump:
103   void Run(Delegate* delegate) override;
104   void Quit() override;
105   void ScheduleWork() override;
106   void ScheduleDelayedWork(
107       const Delegate::NextWorkInfo& next_work_info) override;
108 
109   // Internal methods used for processing the FdWatchSource callbacks. As for
110   // main pump callbacks, they are public for simplicity but should not be used
111   // directly.
112   bool HandleFdWatchCheck(FdWatchController* controller);
113   void HandleFdWatchDispatch(FdWatchController* controller);
114 
115  private:
116   struct GMainContextDeleter {
operatorGMainContextDeleter117     inline void operator()(GMainContext* context) const {
118       if (context) {
119         g_main_context_pop_thread_default(context);
120         g_main_context_unref(context);
121       }
122     }
123   };
124   struct GSourceDeleter {
operatorGSourceDeleter125     inline void operator()(GSource* source) const {
126       if (source) {
127         g_source_destroy(source);
128         g_source_unref(source);
129       }
130     }
131   };
132   bool ShouldQuit() const;
133 
134   // We may make recursive calls to Run, so we save state that needs to be
135   // separate between them in this structure type.
136   struct RunState;
137 
138   raw_ptr<RunState> state_;
139 
140   // Starts tracking a new work item and stores a `ScopedDoWorkItem` in
141   // `state_`.
142   void SetScopedWorkItem();
143   // Gets rid of the current scoped work item.
144   void ClearScopedWorkItem();
145   // Ensures there's a ScopedDoWorkItem at the current run-level. This can be
146   // useful for contexts where the caller can't tell whether they just woke up
147   // or are continuing from native work.
148   void EnsureSetScopedWorkItem();
149   // Ensures there's no ScopedDoWorkItem at the current run-level. This can be
150   // useful in contexts where the caller knows that a sleep is imminent but
151   // doesn't know if the current context captures ongoing work (back from
152   // native).
153   void EnsureClearedScopedWorkItem();
154 
155   // Called before entrance to g_main_context_iteration to record context
156   // related to nesting depth to track native nested loops which would otherwise
157   // be invisible.
158   void OnEntryToGlib();
159   // Cleans up state set in OnEntryToGlib.
160   void OnExitFromGlib();
161   // Forces the pump into a nested state by creating two work items back to
162   // back.
163   void RegisterNested();
164   // Removes all of the pump's ScopedDoWorkItems to remove the state of nesting
165   // which was forced onto the pump.
166   void UnregisterNested();
167   // Nest if pump is not already marked as nested.
168   void NestIfRequired();
169   // Remove the nesting if the pump is nested.
170   void UnnestIfRequired();
171 
172   std::unique_ptr<GMainContext, GMainContextDeleter> owned_context_;
173   // This is a GLib structure that we can add event sources to.  On the main
174   // thread, we use the default GLib context, which is the one to which all GTK
175   // events are dispatched.
176   raw_ptr<GMainContext> context_ = nullptr;
177 
178   // The work source.  It is shared by all calls to Run and destroyed when
179   // the message pump is destroyed.
180   std::unique_ptr<GSource, GSourceDeleter> work_source_;
181 
182   // The observer source.  It is shared by all calls to Run and destroyed when
183   // the message pump is destroyed.
184   std::unique_ptr<GSource, GSourceDeleter> observer_source_;
185 
186   // We use a wakeup pipe to make sure we'll get out of the glib polling phase
187   // when another thread has scheduled us to do some work.  There is a glib
188   // mechanism g_main_context_wakeup, but this won't guarantee that our event's
189   // Dispatch() will be called.
190   int wakeup_pipe_read_;
191   int wakeup_pipe_write_;
192   // Use a unique_ptr to avoid needing the definition of GPollFD in the header.
193   std::unique_ptr<GPollFD> wakeup_gpollfd_;
194 
195   THREAD_CHECKER(watch_fd_caller_checker_);
196 };
197 
198 }  // namespace base
199 
200 #endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
201