xref: /aosp_15_r20/external/cronet/base/files/file_descriptor_watcher_posix.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 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_FILES_FILE_DESCRIPTOR_WATCHER_POSIX_H_
6 #define BASE_FILES_FILE_DESCRIPTOR_WATCHER_POSIX_H_
7 
8 #include <memory>
9 
10 #include "base/auto_reset.h"
11 #include "base/base_export.h"
12 #include "base/dcheck_is_on.h"
13 #include "base/functional/callback.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop/message_pump_for_io.h"
17 #include "base/sequence_checker.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/task/single_thread_task_runner.h"
20 
21 namespace base {
22 
23 class SingleThreadTaskRunner;
24 
25 // The FileDescriptorWatcher API allows callbacks to be invoked when file
26 // descriptors are readable or writable without blocking.
27 //
28 // To enable this API in unit tests, use a TaskEnvironment with
29 // MainThreadType::IO.
30 //
31 // Note: Prefer FileDescriptorWatcher to MessageLoopForIO::WatchFileDescriptor()
32 // for non-critical IO. FileDescriptorWatcher works on threads/sequences without
33 // MessagePumps but involves going through the task queue after being notified
34 // by the OS (a desirablable property for non-critical IO that shouldn't preempt
35 // the main queue).
36 class BASE_EXPORT FileDescriptorWatcher {
37  public:
38   // Instantiated and returned by WatchReadable() or WatchWritable(). The
39   // constructor registers a callback to be invoked when a file descriptor is
40   // readable or writable without blocking and the destructor unregisters it.
41   class Controller {
42    public:
43     Controller(const Controller&) = delete;
44     Controller& operator=(const Controller&) = delete;
45     // Unregisters the callback registered by the constructor.
46     ~Controller();
47 
48    private:
49     friend class FileDescriptorWatcher;
50     class Watcher;
51 
52     // Registers |callback| to be invoked when |fd| is readable or writable
53     // without blocking (depending on |mode|).
54     Controller(MessagePumpForIO::Mode mode,
55                int fd,
56                const RepeatingClosure& callback);
57 
58     // Starts watching the file descriptor.
59     void StartWatching();
60 
61     // Runs |callback_|.
62     void RunCallback();
63 
64     // The callback to run when the watched file descriptor is readable or
65     // writable without blocking.
66     RepeatingClosure callback_;
67 
68     // TaskRunner associated with the MessageLoopForIO that watches the file
69     // descriptor.
70     const scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
71 
72     // Notified by the MessageLoopForIO associated with
73     // |io_thread_task_runner_| when the watched file descriptor is
74     // readable or writable without blocking. Posts a task to run RunCallback()
75     // on the sequence on which the Controller was instantiated. When the
76     // Controller is deleted, ownership of |watcher_| is transfered to a delete
77     // task posted to the MessageLoopForIO. This ensures that |watcher_| isn't
78     // deleted while it is being used by the MessageLoopForIO.
79     raw_ptr<Watcher, AcrossTasksDanglingUntriaged> watcher_;
80 
81     // An event for the watcher to notify controller that it's destroyed.
82     // As the |watcher_| is owned by Controller, always outlives the Watcher.
83     base::WaitableEvent on_watcher_destroyed_;
84 
85     // Validates that the Controller is used on the sequence on which it was
86     // instantiated.
87     SEQUENCE_CHECKER(sequence_checker_);
88 
89     WeakPtrFactory<Controller> weak_factory_{this};
90   };
91 
92   // Registers |io_thread_task_runner| to watch file descriptors for which
93   // callbacks are registered from the current thread via WatchReadable() or
94   // WatchWritable(). |io_thread_task_runner| must post tasks to a thread which
95   // runs a MessagePumpForIO. If it is not the current thread, it must be highly
96   // responsive (i.e. not used to run other expensive tasks such as potentially
97   // blocking I/O) since ~Controller waits for a task posted to it.
98   explicit FileDescriptorWatcher(
99       scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner);
100   FileDescriptorWatcher(const FileDescriptorWatcher&) = delete;
101   FileDescriptorWatcher& operator=(const FileDescriptorWatcher&) = delete;
102   ~FileDescriptorWatcher();
103 
104   // Registers |callback| to be posted on the current sequence when |fd| is
105   // readable or writable without blocking. |callback| is unregistered when the
106   // returned Controller is deleted (deletion must happen on the current
107   // sequence).
108   // Usage note: To call these methods, a FileDescriptorWatcher must have been
109   // instantiated on the current thread and
110   // SequencedTaskRunner::HasCurrentDefault() must return true (these conditions
111   // are met at least on all ThreadPool threads as well as on threads backed by
112   // a MessageLoopForIO). |fd| must outlive the returned Controller. Shutdown
113   // note: notifications aren't guaranteed to be emitted once the bound
114   // (current) SequencedTaskRunner enters its shutdown phase (i.e.
115   // ThreadPool::Shutdown() or Thread::Stop()) regardless of the
116   // SequencedTaskRunner's TaskShutdownBehavior.
117   static std::unique_ptr<Controller> WatchReadable(
118       int fd,
119       const RepeatingClosure& callback);
120   static std::unique_ptr<Controller> WatchWritable(
121       int fd,
122       const RepeatingClosure& callback);
123 
124   // Asserts that usage of this API is allowed on this thread.
125 #if DCHECK_IS_ON()
126   static void AssertAllowed();
127 #else
AssertAllowed()128   static void AssertAllowed() {}
129 #endif
130 
131  private:
io_thread_task_runner()132   scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner() const {
133     return io_thread_task_runner_;
134   }
135 
136   const AutoReset<FileDescriptorWatcher*> resetter_;
137   const scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
138 };
139 
140 }  // namespace base
141 
142 #endif  // BASE_FILES_FILE_DESCRIPTOR_WATCHER_POSIX_H_
143