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
|
// 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_
|