webfilewriter_impl.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/fileapi/webfilewriter_impl.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/bind.h"
8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/platform_file.h"
93240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "base/synchronization/waitable_event.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/child_thread.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/fileapi/file_system_dispatcher.h"
12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "webkit/child/worker_task_runner.h"
13a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using webkit_glue::WorkerTaskRunner;
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace content {
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)FileSystemDispatcher* GetFileSystemDispatcher() {
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return ChildThread::current() ?
22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      ChildThread::current()->file_system_dispatcher() : NULL;
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)typedef FileSystemDispatcher::StatusCallback StatusCallback;
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)typedef FileSystemDispatcher::WriteCallback WriteCallback;
29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// This instance may be created outside main thread but runs mainly
31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// on main thread.
32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class WebFileWriterImpl::WriterBridge
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    : public base::RefCountedThreadSafe<WriterBridge> {
34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public:
353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  WriterBridge(WebFileWriterImpl::Type type)
36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      : request_id_(0),
373240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        thread_id_(WorkerTaskRunner::Instance()->CurrentWorkerId()),
383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        written_bytes_(0) {
393240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (type == WebFileWriterImpl::TYPE_SYNC)
403240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      waitable_event_.reset(new base::WaitableEvent(false, false));
413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Truncate(const GURL& path, int64 offset,
44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                const StatusCallback& status_callback) {
45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status_callback_ = status_callback;
46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!GetFileSystemDispatcher())
47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ChildThread::current()->file_system_dispatcher()->Truncate(
49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        path, offset, &request_id_,
50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&WriterBridge::DidFinish, this));
51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Write(const GURL& path, const GURL& blob_url, int64 offset,
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)             const WriteCallback& write_callback,
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)             const StatusCallback& error_callback) {
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    write_callback_ = write_callback;
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status_callback_ = error_callback;
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!GetFileSystemDispatcher())
59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ChildThread::current()->file_system_dispatcher()->Write(
61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        path, blob_url, offset, &request_id_,
62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&WriterBridge::DidWrite, this),
63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&WriterBridge::DidFinish, this));
64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Cancel(const StatusCallback& status_callback) {
67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status_callback_ = status_callback;
68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!GetFileSystemDispatcher())
69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ChildThread::current()->file_system_dispatcher()->Cancel(
71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        request_id_,
72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&WriterBridge::DidFinish, this));
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  base::WaitableEvent* waitable_event() {
763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return waitable_event_.get();
773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  void WaitAndRun() {
803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    waitable_event_->Wait();
813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    DCHECK(!results_closure_.is_null());
823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    results_closure_.Run();
833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) private:
86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  friend class base::RefCountedThreadSafe<WriterBridge>;
87a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual ~WriterBridge() {}
88a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void DidWrite(int64 bytes, bool complete) {
903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    written_bytes_ += bytes;
913240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (waitable_event_ && !complete)
923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      return;
933240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    PostTaskToWorker(base::Bind(write_callback_, written_bytes_, complete));
94a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
96a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void DidFinish(base::PlatformFileError status) {
97a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostTaskToWorker(base::Bind(status_callback_, status));
98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
99a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
100a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void PostTaskToWorker(const base::Closure& closure) {
1013240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    written_bytes_ = 0;
1023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (!thread_id_) {
1033240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      DCHECK(!waitable_event_);
104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      closure.Run();
1053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      return;
1063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    }
1073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (waitable_event_) {
1083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      results_closure_ = closure;
1093240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      waitable_event_->Signal();
1103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      return;
1113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    }
1123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    WorkerTaskRunner::Instance()->PostTask(thread_id_, closure);
113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  StatusCallback status_callback_;
116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  WriteCallback write_callback_;
117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int request_id_;
118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int thread_id_;
1193240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  int written_bytes_;
1203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  scoped_ptr<base::WaitableEvent> waitable_event_;
1213240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  base::Closure results_closure_;
122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)};
123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)WebFileWriterImpl::WebFileWriterImpl(
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)     const GURL& path, WebKit::WebFileWriterClient* client,
1263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch     Type type,
127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)     base::MessageLoopProxy* main_thread_loop)
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  : WebFileWriterBase(path, client),
129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    main_thread_loop_(main_thread_loop),
1303240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    bridge_(new WriterBridge(type)) {
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)WebFileWriterImpl::~WebFileWriterImpl() {
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WebFileWriterImpl::DoTruncate(const GURL& path, int64 offset) {
137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  RunOnMainThread(base::Bind(&WriterBridge::Truncate, bridge_,
138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      path, offset,
139a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr())));
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WebFileWriterImpl::DoWrite(
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GURL& path, const GURL& blob_url, int64 offset) {
144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  RunOnMainThread(base::Bind(&WriterBridge::Write, bridge_,
145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      path, blob_url, offset,
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(&WebFileWriterImpl::DidWrite, AsWeakPtr()),
147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr())));
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WebFileWriterImpl::DoCancel() {
151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  RunOnMainThread(base::Bind(&WriterBridge::Cancel, bridge_,
152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr())));
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void WebFileWriterImpl::RunOnMainThread(const base::Closure& closure) {
1563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (main_thread_loop_->RunsTasksOnCurrentThread()) {
1573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    DCHECK(!bridge_->waitable_event());
158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    closure.Run();
1593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return;
1603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
1613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  main_thread_loop_->PostTask(FROM_HERE, closure);
1623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (bridge_->waitable_event())
1633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    bridge_->WaitAndRun();
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace content
167