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
base / files / file_descriptor_watcher_posix.h [blame]
// Copyright 2016 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_FILES_FILE_DESCRIPTOR_WATCHER_POSIX_H_
#define BASE_FILES_FILE_DESCRIPTOR_WATCHER_POSIX_H_
#include <memory>
#include "base/auto_reset.h"
#include "base/base_export.h"
#include "base/dcheck_is_on.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_pump_for_io.h"
#include "base/sequence_checker.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/single_thread_task_runner.h"
namespace base {
class SingleThreadTaskRunner;
// The FileDescriptorWatcher API allows callbacks to be invoked when file
// descriptors are readable or writable without blocking.
//
// To enable this API in unit tests, use a TaskEnvironment with
// MainThreadType::IO.
//
// Note: Prefer FileDescriptorWatcher to MessageLoopForIO::WatchFileDescriptor()
// for non-critical IO. FileDescriptorWatcher works on threads/sequences without
// MessagePumps but involves going through the task queue after being notified
// by the OS (a desirablable property for non-critical IO that shouldn't preempt
// the main queue).
class BASE_EXPORT FileDescriptorWatcher {
public:
// Instantiated and returned by WatchReadable() or WatchWritable(). The
// constructor registers a callback to be invoked when a file descriptor is
// readable or writable without blocking and the destructor unregisters it.
class Controller {
public:
Controller(const Controller&) = delete;
Controller& operator=(const Controller&) = delete;
// Unregisters the callback registered by the constructor.
~Controller();
private:
friend class FileDescriptorWatcher;
class Watcher;
// Registers |callback| to be invoked when |fd| is readable or writable
// without blocking (depending on |mode|).
Controller(MessagePumpForIO::Mode mode,
int fd,
const RepeatingClosure& callback);
// Starts watching the file descriptor.
void StartWatching();
// Runs |callback_|.
void RunCallback();
// The callback to run when the watched file descriptor is readable or
// writable without blocking.
RepeatingClosure callback_;
// TaskRunner associated with the MessageLoopForIO that watches the file
// descriptor.
const scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
// Notified by the MessageLoopForIO associated with
// |io_thread_task_runner_| when the watched file descriptor is
// readable or writable without blocking. Posts a task to run RunCallback()
// on the sequence on which the Controller was instantiated. When the
// Controller is deleted, ownership of |watcher_| is transfered to a delete
// task posted to the MessageLoopForIO. This ensures that |watcher_| isn't
// deleted while it is being used by the MessageLoopForIO.
raw_ptr<Watcher, AcrossTasksDanglingUntriaged> watcher_;
// An event for the watcher to notify controller that it's destroyed.
// As the |watcher_| is owned by Controller, always outlives the Watcher.
base::WaitableEvent on_watcher_destroyed_;
// Validates that the Controller is used on the sequence on which it was
// instantiated.
SEQUENCE_CHECKER(sequence_checker_);
WeakPtrFactory<Controller> weak_factory_{this};
};
// Registers |io_thread_task_runner| to watch file descriptors for which
// callbacks are registered from the current thread via WatchReadable() or
// WatchWritable(). |io_thread_task_runner| must post tasks to a thread which
// runs a MessagePumpForIO. If it is not the current thread, it must be highly
// responsive (i.e. not used to run other expensive tasks such as potentially
// blocking I/O) since ~Controller waits for a task posted to it.
explicit FileDescriptorWatcher(
scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner);
FileDescriptorWatcher(const FileDescriptorWatcher&) = delete;
FileDescriptorWatcher& operator=(const FileDescriptorWatcher&) = delete;
~FileDescriptorWatcher();
// Registers |callback| to be posted on the current sequence when |fd| is
// readable or writable without blocking. |callback| is unregistered when the
// returned Controller is deleted (deletion must happen on the current
// sequence).
// Usage note: To call these methods, a FileDescriptorWatcher must have been
// instantiated on the current thread and
// SequencedTaskRunner::HasCurrentDefault() must return true (these conditions
// are met at least on all ThreadPool threads as well as on threads backed by
// a MessageLoopForIO). |fd| must outlive the returned Controller. Shutdown
// note: notifications aren't guaranteed to be emitted once the bound
// (current) SequencedTaskRunner enters its shutdown phase (i.e.
// ThreadPool::Shutdown() or Thread::Stop()) regardless of the
// SequencedTaskRunner's TaskShutdownBehavior.
static std::unique_ptr<Controller> WatchReadable(
int fd,
const RepeatingClosure& callback);
static std::unique_ptr<Controller> WatchWritable(
int fd,
const RepeatingClosure& callback);
// Asserts that usage of this API is allowed on this thread.
#if DCHECK_IS_ON()
static void AssertAllowed();
#else
static void AssertAllowed() {}
#endif
private:
scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner() const {
return io_thread_task_runner_;
}
const AutoReset<FileDescriptorWatcher*> resetter_;
const scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
};
} // namespace base
#endif // BASE_FILES_FILE_DESCRIPTOR_WATCHER_POSIX_H_