• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 #include "net/disk_cache/blockfile/in_flight_io.h"
6 
7 #include "base/functional/bind.h"
8 #include "base/location.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/task/sequenced_task_runner.h"
11 #include "base/task/single_thread_task_runner.h"
12 #include "base/threading/thread_restrictions.h"
13 
14 namespace disk_cache {
15 
BackgroundIO(InFlightIO * controller)16 BackgroundIO::BackgroundIO(InFlightIO* controller)
17     : io_completed_(base::WaitableEvent::ResetPolicy::MANUAL,
18                     base::WaitableEvent::InitialState::NOT_SIGNALED),
19       controller_(controller) {}
20 
21 // Runs on the primary thread.
OnIOSignalled()22 void BackgroundIO::OnIOSignalled() {
23   if (controller_) {
24     did_notify_controller_io_signalled_ = true;
25     controller_->InvokeCallback(this, false);
26   }
27 }
28 
Cancel()29 void BackgroundIO::Cancel() {
30   // controller_ may be in use from the background thread at this time.
31   base::AutoLock lock(controller_lock_);
32   DCHECK(controller_);
33   controller_ = nullptr;
34 }
35 
ClearController()36 void BackgroundIO::ClearController() {
37   controller_ = nullptr;
38 }
39 
40 BackgroundIO::~BackgroundIO() = default;
41 
42 // ---------------------------------------------------------------------------
43 
InFlightIO()44 InFlightIO::InFlightIO()
45     : callback_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
46 }
47 
48 InFlightIO::~InFlightIO() = default;
49 
50 // Runs on the background thread.
NotifyController()51 void BackgroundIO::NotifyController() {
52   base::AutoLock lock(controller_lock_);
53   if (controller_)
54     controller_->OnIOComplete(this);
55 }
56 
WaitForPendingIO()57 void InFlightIO::WaitForPendingIO() {
58   while (!io_list_.empty()) {
59     // Block the current thread until all pending IO completes.
60     auto it = io_list_.begin();
61     InvokeCallback(it->get(), true);
62   }
63 }
64 
DropPendingIO()65 void InFlightIO::DropPendingIO() {
66   while (!io_list_.empty()) {
67     auto it = io_list_.begin();
68     BackgroundIO* operation = it->get();
69     operation->Cancel();
70     DCHECK(io_list_.find(operation) != io_list_.end());
71     io_list_.erase(base::WrapRefCounted(operation));
72   }
73 }
74 
75 // Runs in a background sequence.
OnIOComplete(BackgroundIO * operation)76 void InFlightIO::OnIOComplete(BackgroundIO* operation) {
77 #if DCHECK_IS_ON()
78   if (callback_task_runner_->RunsTasksInCurrentSequence()) {
79     DCHECK(single_thread_ || !running_);
80     single_thread_ = true;
81   }
82 #endif
83 
84   callback_task_runner_->PostTask(
85       FROM_HERE, base::BindOnce(&BackgroundIO::OnIOSignalled, operation));
86   operation->io_completed()->Signal();
87 }
88 
89 // Runs on the primary thread.
InvokeCallback(BackgroundIO * operation,bool cancel_task)90 void InFlightIO::InvokeCallback(BackgroundIO* operation, bool cancel_task) {
91   {
92     // http://crbug.com/74623
93     base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
94     operation->io_completed()->Wait();
95   }
96   running_ = true;
97 
98   if (cancel_task)
99     operation->Cancel();
100 
101   // Make sure that we remove the operation from the list before invoking the
102   // callback (so that a subsequent cancel does not invoke the callback again).
103   DCHECK(io_list_.find(operation) != io_list_.end());
104   DCHECK(!operation->HasOneRef());
105   io_list_.erase(base::WrapRefCounted(operation));
106   OnOperationComplete(operation, cancel_task);
107 }
108 
109 // Runs on the primary thread.
OnOperationPosted(BackgroundIO * operation)110 void InFlightIO::OnOperationPosted(BackgroundIO* operation) {
111   DCHECK(callback_task_runner_->RunsTasksInCurrentSequence());
112   io_list_.insert(base::WrapRefCounted(operation));
113 }
114 
115 }  // namespace disk_cache
116