#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
#include <memory>
#include <tuple>
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_pump.h"
#include "base/message_loop/message_pump_buildflags.h"
#include "base/message_loop/watchable_io_message_pump_posix.h"
#include "base/threading/thread_checker.h"
#include "third_party/libevent/event.h"
struct event_base;
struct event;
namespace base {
class MessagePumpEpoll;
class BASE_EXPORT MessagePumpLibevent : public MessagePump,
public WatchableIOMessagePumpPosix {
public:
class FdWatchController;
struct EpollInterestParams {
int fd;
bool read;
bool write;
bool one_shot;
bool IsEqual(const EpollInterestParams& rhs) const {
return std::tie(fd, read, write, one_shot) ==
std::tie(rhs.fd, rhs.read, rhs.write, rhs.one_shot);
}
};
class EpollInterest : public RefCounted<EpollInterest> {
public:
EpollInterest(FdWatchController* controller,
const EpollInterestParams& params);
EpollInterest(const EpollInterest&) = delete;
EpollInterest& operator=(const EpollInterest&) = delete;
FdWatchController* controller() { return controller_; }
const EpollInterestParams& params() const { return params_; }
bool active() const { return active_; }
void set_active(bool active) { active_ = active; }
bool was_controller_destroyed() const { return was_controller_destroyed_; }
void WatchForControllerDestruction() {
DCHECK(!controller_->was_destroyed_);
controller_->was_destroyed_ = &was_controller_destroyed_;
}
void StopWatchingForControllerDestruction() {
if (!was_controller_destroyed_) {
DCHECK_EQ(controller_->was_destroyed_, &was_controller_destroyed_);
controller_->was_destroyed_ = nullptr;
}
}
private:
friend class RefCounted<EpollInterest>;
~EpollInterest();
const raw_ptr<FdWatchController, DanglingUntriaged> controller_;
const EpollInterestParams params_;
bool active_ = true;
bool was_controller_destroyed_ = false;
};
class FdWatchController : public FdWatchControllerInterface {
public:
explicit FdWatchController(const Location& from_here);
FdWatchController(const FdWatchController&) = delete;
FdWatchController& operator=(const FdWatchController&) = delete;
~FdWatchController() override;
bool StopWatchingFileDescriptor() override;
private:
friend class MessagePumpEpoll;
friend class MessagePumpLibevent;
friend class MessagePumpLibeventTest;
void set_watcher(FdWatcher* watcher) { watcher_ = watcher; }
void set_libevent_pump(MessagePumpLibevent* pump) { libevent_pump_ = pump; }
MessagePumpLibevent* libevent_pump() const { return libevent_pump_; }
void Init(std::unique_ptr<event> e);
std::unique_ptr<event> ReleaseEvent();
void OnFileCanReadWithoutBlocking(int fd, MessagePumpLibevent* pump);
void OnFileCanWriteWithoutBlocking(int fd, MessagePumpLibevent* pump);
void set_epoll_pump(WeakPtr<MessagePumpEpoll> pump) {
epoll_pump_ = std::move(pump);
}
const scoped_refptr<EpollInterest>& epoll_interest() const {
return epoll_interest_;
}
const scoped_refptr<EpollInterest>& AssignEpollInterest(
const EpollInterestParams& params);
void OnFdReadable();
void OnFdWritable();
raw_ptr<FdWatcher> watcher_ = nullptr;
raw_ptr<bool> was_destroyed_ = nullptr;
std::unique_ptr<event> event_;
raw_ptr<MessagePumpLibevent, DisableDanglingPtrDetection> libevent_pump_ =
nullptr;
WeakPtr<MessagePumpEpoll> epoll_pump_;
scoped_refptr<EpollInterest> epoll_interest_;
};
MessagePumpLibevent();
#if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL)
enum { kUseEpoll };
explicit MessagePumpLibevent(decltype(kUseEpoll));
#endif
MessagePumpLibevent(const MessagePumpLibevent&) = delete;
MessagePumpLibevent& operator=(const MessagePumpLibevent&) = delete;
~MessagePumpLibevent() override;
static void InitializeFeatures();
bool WatchFileDescriptor(int fd,
bool persistent,
int mode,
FdWatchController* controller,
FdWatcher* delegate);
void Run(Delegate* delegate) override;
void Quit() override;
void ScheduleWork() override;
void ScheduleDelayedWork(
const Delegate::NextWorkInfo& next_work_info) override;
private:
friend class MessagePumpLibeventTest;
bool Init();
static void OnLibeventNotification(int fd, short flags, void* context);
static void OnWakeup(int socket, short flags, void* context);
struct RunState {
explicit RunState(Delegate* delegate_in) : delegate(delegate_in) {}
RAW_PTR_EXCLUSION Delegate* const delegate;
bool should_quit = false;
};
#if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL)
std::unique_ptr<MessagePumpEpoll> epoll_pump_;
#endif
raw_ptr<RunState> run_state_ = nullptr;
bool processed_io_events_ = false;
struct EventBaseFree {
inline void operator()(event_base* e) const {
if (e)
event_base_free(e);
}
};
std::unique_ptr<event_base, EventBaseFree> event_base_{event_base_new()};
int wakeup_pipe_in_ = -1;
int wakeup_pipe_out_ = -1;
std::unique_ptr<event> wakeup_event_;
ThreadChecker watch_file_descriptor_caller_checker_;
};
}
#endif