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