message_pump_epoll.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_EPOLL_H_
  5. #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_EPOLL_H_
  6. #include <sys/epoll.h>
  7. #include <cstdint>
  8. #include <map>
  9. #include "base/base_export.h"
  10. #include "base/containers/stack_container.h"
  11. #include "base/files/scoped_file.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/memory/ref_counted.h"
  14. #include "base/memory/weak_ptr.h"
  15. #include "base/message_loop/message_pump.h"
  16. #include "base/message_loop/message_pump_libevent.h"
  17. #include "base/message_loop/watchable_io_message_pump_posix.h"
  18. #include "base/threading/thread_checker.h"
  19. #include "base/time/time.h"
  20. namespace base {
  21. // A MessagePump implementation suitable for I/O message loops on Linux-based
  22. // systems with epoll API support.
  23. class BASE_EXPORT MessagePumpEpoll : public MessagePump,
  24. public WatchableIOMessagePumpPosix {
  25. using InterestParams = MessagePumpLibevent::EpollInterestParams;
  26. using Interest = MessagePumpLibevent::EpollInterest;
  27. public:
  28. using FdWatchController = MessagePumpLibevent::FdWatchController;
  29. MessagePumpEpoll();
  30. MessagePumpEpoll(const MessagePumpEpoll&) = delete;
  31. MessagePumpEpoll& operator=(const MessagePumpEpoll&) = delete;
  32. ~MessagePumpEpoll() override;
  33. bool WatchFileDescriptor(int fd,
  34. bool persistent,
  35. int mode,
  36. FdWatchController* controller,
  37. FdWatcher* watcher);
  38. // MessagePump methods:
  39. void Run(Delegate* delegate) override;
  40. void Quit() override;
  41. void ScheduleWork() override;
  42. void ScheduleDelayedWork(
  43. const Delegate::NextWorkInfo& next_work_info) override;
  44. private:
  45. friend class MessagePumpLibevent;
  46. friend class MessagePumpLibeventTest;
  47. // The WatchFileDescriptor API supports multiple FdWatchControllers watching
  48. // the same file descriptor, potentially for different events; but the epoll
  49. // API only supports a single interest list entry per unique file descriptor.
  50. //
  51. // EpollEventEntry tracks all epoll state relevant to a single file
  52. // descriptor, including references to all active and inactive Interests
  53. // concerned with that descriptor. This is used to derive a single aggregate
  54. // interest entry for the descriptor when manipulating epoll.
  55. struct EpollEventEntry {
  56. explicit EpollEventEntry(int fd);
  57. EpollEventEntry(const EpollEventEntry&) = delete;
  58. EpollEventEntry& operator=(const EpollEventEntry&) = delete;
  59. ~EpollEventEntry();
  60. // Returns the combined set of epoll event flags which should be monitored
  61. // by the epoll instance for `fd`. This is based on a combination of the
  62. // parameters of all currently active elements in `interests`. Namely:
  63. // - EPOLLIN is set if any active Interest wants to `read`.
  64. // - EPOLLOUT is set if any active Interest wants to `write`.
  65. // - EPOLLONESHOT is set if all active Interests are one-shot.
  66. uint32_t ComputeActiveEvents();
  67. // The file descriptor to which this entry pertains.
  68. const int fd;
  69. // A cached copy of the last known epoll event bits registered for this
  70. // descriptor on the epoll instance.
  71. uint32_t registered_events = 0;
  72. // A collection of all the interests regarding `fd` on this message pump.
  73. // The small amount of inline storage avoids heap allocation in virtually
  74. // all real scenarios, since there's little practical value in having more
  75. // than two controllers (e.g. one reader and one writer) watch the same
  76. // descriptor on the same thread.
  77. StackVector<scoped_refptr<Interest>, 2> interests;
  78. };
  79. // State which lives on the stack within Run(), to support nested run loops.
  80. struct RunState {
  81. explicit RunState(Delegate* delegate) : delegate(delegate) {}
  82. // `delegate` is not a raw_ptr<...> for performance reasons (based on
  83. // analysis of sampling profiler data and tab_search:top100:2020).
  84. RAW_PTR_EXCLUSION Delegate* const delegate;
  85. // Used to flag that the current Run() invocation should return ASAP.
  86. bool should_quit = false;
  87. };
  88. void AddEpollEvent(EpollEventEntry& entry);
  89. void UpdateEpollEvent(EpollEventEntry& entry);
  90. void UnregisterInterest(const scoped_refptr<Interest>& interest);
  91. bool WaitForEpollEvent(TimeDelta timeout);
  92. void OnEpollEvent(const epoll_event& e);
  93. void HandleEvent(int fd,
  94. bool can_read,
  95. bool can_write,
  96. FdWatchController* controller);
  97. void HandleWakeUp();
  98. // Null if Run() is not currently executing. Otherwise it's a pointer into the
  99. // stack of the innermost nested Run() invocation.
  100. RunState* run_state_ = nullptr;
  101. // Mapping of all file descriptors currently watched by this message pump.
  102. // std::map was chosen because (1) the number of elements can vary widely,
  103. // (2) we don't do frequent lookups, and (3) values need stable addresses
  104. // across insertion or removal of other elements.
  105. std::map<int, EpollEventEntry> entries_;
  106. // The epoll instance used by this message pump to monitor file descriptors.
  107. ScopedFD epoll_;
  108. // An eventfd object used to wake the pump's thread when scheduling new work.
  109. ScopedFD wake_event_;
  110. // WatchFileDescriptor() must be called from this thread, and so must
  111. // FdWatchController::StopWatchingFileDescriptor().
  112. THREAD_CHECKER(thread_checker_);
  113. WeakPtrFactory<MessagePumpEpoll> weak_ptr_factory_{this};
  114. };
  115. } // namespace base
  116. #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_EPOLL_H_