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
3 // found in the LICENSE file.
5 #include "content/child/fileapi/webfilewriter_impl.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "content/child/child_thread_impl.h"
11 #include "content/child/fileapi/file_system_dispatcher.h"
12 #include "content/child/worker_task_runner.h"
18 FileSystemDispatcher
* GetFileSystemDispatcher() {
19 return ChildThreadImpl::current() ?
20 ChildThreadImpl::current()->file_system_dispatcher() : NULL
;
25 typedef FileSystemDispatcher::StatusCallback StatusCallback
;
26 typedef FileSystemDispatcher::WriteCallback WriteCallback
;
28 // This instance may be created outside main thread but runs mainly
30 class WebFileWriterImpl::WriterBridge
31 : public base::RefCountedThreadSafe
<WriterBridge
> {
33 WriterBridge(WebFileWriterImpl::Type type
)
35 running_on_worker_(WorkerTaskRunner::Instance()->CurrentWorkerId() > 0),
36 task_runner_(running_on_worker_
? base::ThreadTaskRunnerHandle::Get()
39 if (type
== WebFileWriterImpl::TYPE_SYNC
)
40 waitable_event_
.reset(new base::WaitableEvent(false, false));
43 void Truncate(const GURL
& path
, int64 offset
,
44 const StatusCallback
& status_callback
) {
45 status_callback_
= status_callback
;
46 if (!GetFileSystemDispatcher())
48 ChildThreadImpl::current()->file_system_dispatcher()->Truncate(
49 path
, offset
, &request_id_
,
50 base::Bind(&WriterBridge::DidFinish
, this));
53 void Write(const GURL
& path
, const std::string
& id
, int64 offset
,
54 const WriteCallback
& write_callback
,
55 const StatusCallback
& error_callback
) {
56 write_callback_
= write_callback
;
57 status_callback_
= error_callback
;
58 if (!GetFileSystemDispatcher())
60 ChildThreadImpl::current()->file_system_dispatcher()->Write(
61 path
, id
, offset
, &request_id_
,
62 base::Bind(&WriterBridge::DidWrite
, this),
63 base::Bind(&WriterBridge::DidFinish
, this));
66 void Cancel(const StatusCallback
& status_callback
) {
67 status_callback_
= status_callback
;
68 if (!GetFileSystemDispatcher())
70 ChildThreadImpl::current()->file_system_dispatcher()->Cancel(
72 base::Bind(&WriterBridge::DidFinish
, this));
75 base::WaitableEvent
* waitable_event() {
76 return waitable_event_
.get();
80 waitable_event_
->Wait();
81 DCHECK(!results_closure_
.is_null());
82 results_closure_
.Run();
86 friend class base::RefCountedThreadSafe
<WriterBridge
>;
87 virtual ~WriterBridge() {}
89 void DidWrite(int64 bytes
, bool complete
) {
90 written_bytes_
+= bytes
;
91 if (waitable_event_
&& !complete
)
93 PostTaskToWorker(base::Bind(write_callback_
, written_bytes_
, complete
));
96 void DidFinish(base::File::Error status
) {
97 PostTaskToWorker(base::Bind(status_callback_
, status
));
100 void PostTaskToWorker(const base::Closure
& closure
) {
102 if (!running_on_worker_
) {
103 DCHECK(!waitable_event_
);
107 DCHECK(task_runner_
);
108 if (waitable_event_
) {
109 results_closure_
= closure
;
110 waitable_event_
->Signal();
113 task_runner_
->PostTask(FROM_HERE
, closure
);
116 StatusCallback status_callback_
;
117 WriteCallback write_callback_
;
119 const bool running_on_worker_
;
120 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
122 scoped_ptr
<base::WaitableEvent
> waitable_event_
;
123 base::Closure results_closure_
;
126 WebFileWriterImpl::WebFileWriterImpl(
127 const GURL
& path
, blink::WebFileWriterClient
* client
,
129 const scoped_refptr
<base::SingleThreadTaskRunner
>& main_thread_task_runner
)
130 : WebFileWriterBase(path
, client
),
131 main_thread_task_runner_(main_thread_task_runner
),
132 bridge_(new WriterBridge(type
)) {
135 WebFileWriterImpl::~WebFileWriterImpl() {
138 void WebFileWriterImpl::DoTruncate(const GURL
& path
, int64 offset
) {
139 RunOnMainThread(base::Bind(&WriterBridge::Truncate
, bridge_
,
141 base::Bind(&WebFileWriterImpl::DidFinish
, AsWeakPtr())));
144 void WebFileWriterImpl::DoWrite(
145 const GURL
& path
, const std::string
& blob_id
, int64 offset
) {
146 RunOnMainThread(base::Bind(&WriterBridge::Write
, bridge_
,
147 path
, blob_id
, offset
,
148 base::Bind(&WebFileWriterImpl::DidWrite
, AsWeakPtr()),
149 base::Bind(&WebFileWriterImpl::DidFinish
, AsWeakPtr())));
152 void WebFileWriterImpl::DoCancel() {
153 RunOnMainThread(base::Bind(&WriterBridge::Cancel
, bridge_
,
154 base::Bind(&WebFileWriterImpl::DidFinish
, AsWeakPtr())));
157 void WebFileWriterImpl::RunOnMainThread(const base::Closure
& closure
) {
158 if (main_thread_task_runner_
->RunsTasksOnCurrentThread()) {
159 DCHECK(!bridge_
->waitable_event());
163 main_thread_task_runner_
->PostTask(FROM_HERE
, closure
);
164 if (bridge_
->waitable_event())
165 bridge_
->WaitAndRun();
168 } // namespace content