OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/child/fileapi/webfilewriter_impl.h" | 5 #include "content/child/fileapi/webfilewriter_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/platform_file.h" | 8 #include "base/platform_file.h" |
| 9 #include "base/synchronization/waitable_event.h" |
9 #include "content/child/child_thread.h" | 10 #include "content/child/child_thread.h" |
10 #include "content/child/fileapi/file_system_dispatcher.h" | 11 #include "content/child/fileapi/file_system_dispatcher.h" |
11 #include "webkit/child/worker_task_runner.h" | 12 #include "webkit/child/worker_task_runner.h" |
12 | 13 |
13 using webkit_glue::WorkerTaskRunner; | 14 using webkit_glue::WorkerTaskRunner; |
14 | 15 |
15 namespace content { | 16 namespace content { |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 FileSystemDispatcher* GetFileSystemDispatcher() { | 20 FileSystemDispatcher* GetFileSystemDispatcher() { |
20 return ChildThread::current() ? | 21 return ChildThread::current() ? |
21 ChildThread::current()->file_system_dispatcher() : NULL; | 22 ChildThread::current()->file_system_dispatcher() : NULL; |
22 } | 23 } |
23 | 24 |
24 } // namespace | 25 } // namespace |
25 | 26 |
26 typedef FileSystemDispatcher::StatusCallback StatusCallback; | 27 typedef FileSystemDispatcher::StatusCallback StatusCallback; |
27 typedef FileSystemDispatcher::WriteCallback WriteCallback; | 28 typedef FileSystemDispatcher::WriteCallback WriteCallback; |
28 | 29 |
29 // This instance may be created outside main thread but runs mainly | 30 // This instance may be created outside main thread but runs mainly |
30 // on main thread. | 31 // on main thread. |
31 class WebFileWriterImpl::WriterBridge | 32 class WebFileWriterImpl::WriterBridge |
32 : public base::RefCountedThreadSafe<WriterBridge> { | 33 : public base::RefCountedThreadSafe<WriterBridge> { |
33 public: | 34 public: |
34 WriterBridge() | 35 WriterBridge(WebFileWriterImpl::Type type) |
35 : request_id_(0), | 36 : request_id_(0), |
36 thread_id_(WorkerTaskRunner::Instance()->CurrentWorkerId()) {} | 37 thread_id_(WorkerTaskRunner::Instance()->CurrentWorkerId()), |
| 38 written_bytes_(0) { |
| 39 if (type == WebFileWriterImpl::TYPE_SYNC) |
| 40 waitable_event_.reset(new base::WaitableEvent(false, false)); |
| 41 } |
37 | 42 |
38 void Truncate(const GURL& path, int64 offset, | 43 void Truncate(const GURL& path, int64 offset, |
39 const StatusCallback& status_callback) { | 44 const StatusCallback& status_callback) { |
40 status_callback_ = status_callback; | 45 status_callback_ = status_callback; |
41 if (!GetFileSystemDispatcher()) | 46 if (!GetFileSystemDispatcher()) |
42 return; | 47 return; |
43 ChildThread::current()->file_system_dispatcher()->Truncate( | 48 ChildThread::current()->file_system_dispatcher()->Truncate( |
44 path, offset, &request_id_, | 49 path, offset, &request_id_, |
45 base::Bind(&WriterBridge::DidFinish, this)); | 50 base::Bind(&WriterBridge::DidFinish, this)); |
46 } | 51 } |
(...skipping 13 matching lines...) Expand all Loading... |
60 | 65 |
61 void Cancel(const StatusCallback& status_callback) { | 66 void Cancel(const StatusCallback& status_callback) { |
62 status_callback_ = status_callback; | 67 status_callback_ = status_callback; |
63 if (!GetFileSystemDispatcher()) | 68 if (!GetFileSystemDispatcher()) |
64 return; | 69 return; |
65 ChildThread::current()->file_system_dispatcher()->Cancel( | 70 ChildThread::current()->file_system_dispatcher()->Cancel( |
66 request_id_, | 71 request_id_, |
67 base::Bind(&WriterBridge::DidFinish, this)); | 72 base::Bind(&WriterBridge::DidFinish, this)); |
68 } | 73 } |
69 | 74 |
| 75 base::WaitableEvent* waitable_event() { |
| 76 return waitable_event_.get(); |
| 77 } |
| 78 |
| 79 void WaitAndRun() { |
| 80 waitable_event_->Wait(); |
| 81 DCHECK(!results_closure_.is_null()); |
| 82 results_closure_.Run(); |
| 83 } |
| 84 |
70 private: | 85 private: |
71 friend class base::RefCountedThreadSafe<WriterBridge>; | 86 friend class base::RefCountedThreadSafe<WriterBridge>; |
72 virtual ~WriterBridge() {} | 87 virtual ~WriterBridge() {} |
73 | 88 |
74 void DidWrite(int64 bytes, bool complete) { | 89 void DidWrite(int64 bytes, bool complete) { |
75 PostTaskToWorker(base::Bind(write_callback_, bytes, complete)); | 90 written_bytes_ += bytes; |
| 91 if (waitable_event_ && !complete) |
| 92 return; |
| 93 PostTaskToWorker(base::Bind(write_callback_, written_bytes_, complete)); |
76 } | 94 } |
77 | 95 |
78 void DidFinish(base::PlatformFileError status) { | 96 void DidFinish(base::PlatformFileError status) { |
79 PostTaskToWorker(base::Bind(status_callback_, status)); | 97 PostTaskToWorker(base::Bind(status_callback_, status)); |
80 } | 98 } |
81 | 99 |
82 void PostTaskToWorker(const base::Closure& closure) { | 100 void PostTaskToWorker(const base::Closure& closure) { |
83 if (!thread_id_) | 101 written_bytes_ = 0; |
| 102 if (!thread_id_) { |
| 103 DCHECK(!waitable_event_); |
84 closure.Run(); | 104 closure.Run(); |
85 else | 105 return; |
86 WorkerTaskRunner::Instance()->PostTask(thread_id_, closure); | 106 } |
| 107 if (waitable_event_) { |
| 108 results_closure_ = closure; |
| 109 waitable_event_->Signal(); |
| 110 return; |
| 111 } |
| 112 WorkerTaskRunner::Instance()->PostTask(thread_id_, closure); |
87 } | 113 } |
88 | 114 |
89 StatusCallback status_callback_; | 115 StatusCallback status_callback_; |
90 WriteCallback write_callback_; | 116 WriteCallback write_callback_; |
91 int request_id_; | 117 int request_id_; |
92 int thread_id_; | 118 int thread_id_; |
| 119 int written_bytes_; |
| 120 scoped_ptr<base::WaitableEvent> waitable_event_; |
| 121 base::Closure results_closure_; |
93 }; | 122 }; |
94 | 123 |
95 WebFileWriterImpl::WebFileWriterImpl( | 124 WebFileWriterImpl::WebFileWriterImpl( |
96 const GURL& path, WebKit::WebFileWriterClient* client, | 125 const GURL& path, WebKit::WebFileWriterClient* client, |
| 126 Type type, |
97 base::MessageLoopProxy* main_thread_loop) | 127 base::MessageLoopProxy* main_thread_loop) |
98 : WebFileWriterBase(path, client), | 128 : WebFileWriterBase(path, client), |
99 main_thread_loop_(main_thread_loop), | 129 main_thread_loop_(main_thread_loop), |
100 bridge_(new WriterBridge) { | 130 bridge_(new WriterBridge(type)) { |
101 } | 131 } |
102 | 132 |
103 WebFileWriterImpl::~WebFileWriterImpl() { | 133 WebFileWriterImpl::~WebFileWriterImpl() { |
104 } | 134 } |
105 | 135 |
106 void WebFileWriterImpl::DoTruncate(const GURL& path, int64 offset) { | 136 void WebFileWriterImpl::DoTruncate(const GURL& path, int64 offset) { |
107 RunOnMainThread(base::Bind(&WriterBridge::Truncate, bridge_, | 137 RunOnMainThread(base::Bind(&WriterBridge::Truncate, bridge_, |
108 path, offset, | 138 path, offset, |
109 base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()))); | 139 base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()))); |
110 } | 140 } |
111 | 141 |
112 void WebFileWriterImpl::DoWrite( | 142 void WebFileWriterImpl::DoWrite( |
113 const GURL& path, const GURL& blob_url, int64 offset) { | 143 const GURL& path, const GURL& blob_url, int64 offset) { |
114 RunOnMainThread(base::Bind(&WriterBridge::Write, bridge_, | 144 RunOnMainThread(base::Bind(&WriterBridge::Write, bridge_, |
115 path, blob_url, offset, | 145 path, blob_url, offset, |
116 base::Bind(&WebFileWriterImpl::DidWrite, AsWeakPtr()), | 146 base::Bind(&WebFileWriterImpl::DidWrite, AsWeakPtr()), |
117 base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()))); | 147 base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()))); |
118 } | 148 } |
119 | 149 |
120 void WebFileWriterImpl::DoCancel() { | 150 void WebFileWriterImpl::DoCancel() { |
121 RunOnMainThread(base::Bind(&WriterBridge::Cancel, bridge_, | 151 RunOnMainThread(base::Bind(&WriterBridge::Cancel, bridge_, |
122 base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()))); | 152 base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()))); |
123 } | 153 } |
124 | 154 |
125 void WebFileWriterImpl::RunOnMainThread(const base::Closure& closure) { | 155 void WebFileWriterImpl::RunOnMainThread(const base::Closure& closure) { |
126 if (main_thread_loop_->RunsTasksOnCurrentThread()) | 156 if (main_thread_loop_->RunsTasksOnCurrentThread()) { |
| 157 DCHECK(!bridge_->waitable_event()); |
127 closure.Run(); | 158 closure.Run(); |
128 else | 159 return; |
129 main_thread_loop_->PostTask(FROM_HERE, closure); | 160 } |
| 161 main_thread_loop_->PostTask(FROM_HERE, closure); |
| 162 if (bridge_->waitable_event()) |
| 163 bridge_->WaitAndRun(); |
130 } | 164 } |
131 | 165 |
132 } // namespace content | 166 } // namespace content |
OLD | NEW |