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
|
// 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_
|