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