in_flight_io.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
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/bind.h"
8#include "base/location.h"
9#include "base/logging.h"
10#include "base/threading/thread_restrictions.h"
11
12namespace disk_cache {
13
14BackgroundIO::BackgroundIO(InFlightIO* controller)
15    : result_(-1), io_completed_(true, false), controller_(controller) {
16}
17
18// Runs on the primary thread.
19void BackgroundIO::OnIOSignalled() {
20  if (controller_)
21    controller_->InvokeCallback(this, false);
22}
23
24void BackgroundIO::Cancel() {
25  // controller_ may be in use from the background thread at this time.
26  base::AutoLock lock(controller_lock_);
27  DCHECK(controller_);
28  controller_ = NULL;
29}
30
31BackgroundIO::~BackgroundIO() {
32}
33
34// ---------------------------------------------------------------------------
35
36InFlightIO::InFlightIO()
37    : callback_thread_(base::MessageLoopProxy::current()),
38      running_(false), single_thread_(false) {
39}
40
41InFlightIO::~InFlightIO() {
42}
43
44// Runs on the background thread.
45void BackgroundIO::NotifyController() {
46  base::AutoLock lock(controller_lock_);
47  if (controller_)
48    controller_->OnIOComplete(this);
49}
50
51void InFlightIO::WaitForPendingIO() {
52  while (!io_list_.empty()) {
53    // Block the current thread until all pending IO completes.
54    IOList::iterator it = io_list_.begin();
55    InvokeCallback(it->get(), true);
56  }
57}
58
59void InFlightIO::DropPendingIO() {
60  while (!io_list_.empty()) {
61    IOList::iterator it = io_list_.begin();
62    BackgroundIO* operation = it->get();
63    operation->Cancel();
64    DCHECK(io_list_.find(operation) != io_list_.end());
65    io_list_.erase(make_scoped_refptr(operation));
66  }
67}
68
69// Runs on a background thread.
70void InFlightIO::OnIOComplete(BackgroundIO* operation) {
71#ifndef NDEBUG
72  if (callback_thread_->BelongsToCurrentThread()) {
73    DCHECK(single_thread_ || !running_);
74    single_thread_ = true;
75  }
76#endif
77
78  callback_thread_->PostTask(FROM_HERE,
79                             base::Bind(&BackgroundIO::OnIOSignalled,
80                                        operation));
81  operation->io_completed()->Signal();
82}
83
84// Runs on the primary thread.
85void InFlightIO::InvokeCallback(BackgroundIO* operation, bool cancel_task) {
86  {
87    // http://crbug.com/74623
88    base::ThreadRestrictions::ScopedAllowWait allow_wait;
89    operation->io_completed()->Wait();
90  }
91  running_ = true;
92
93  if (cancel_task)
94    operation->Cancel();
95
96  // Make sure that we remove the operation from the list before invoking the
97  // callback (so that a subsequent cancel does not invoke the callback again).
98  DCHECK(io_list_.find(operation) != io_list_.end());
99  DCHECK(!operation->HasOneRef());
100  io_list_.erase(make_scoped_refptr(operation));
101  OnOperationComplete(operation, cancel_task);
102}
103
104// Runs on the primary thread.
105void InFlightIO::OnOperationPosted(BackgroundIO* operation) {
106  DCHECK(callback_thread_->BelongsToCurrentThread());
107  io_list_.insert(make_scoped_refptr(operation));
108}
109
110}  // namespace disk_cache
111