Chromium Code Reviews| Index: content/renderer/indexed_db_message_filter.cc |
| diff --git a/content/renderer/indexed_db_message_filter.cc b/content/renderer/indexed_db_message_filter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c2bf218aac021548afcaa894d29a1f2ad9947885 |
| --- /dev/null |
| +++ b/content/renderer/indexed_db_message_filter.cc |
| @@ -0,0 +1,262 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/renderer/indexed_db_message_filter.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/location.h" |
| +#include "content/common/indexed_db_messages.h" |
| +#include "content/renderer/indexed_db_dispatcher.h" |
| +#include "content/renderer/render_thread_impl.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebWorkerRunLoop.h" |
| + |
| +using WebKit::WebWorkerRunLoop; |
| + |
| +IndexedDBMessageFilter::IndexedDBMessageFilter() : |
| + WebCoreWorkerTracker(), |
| + main_thread_loop_proxy_(base::MessageLoopProxy::current()), |
| + main_thread_dispatcher_(new IndexedDBDispatcher(this)) { |
| +} |
| + |
| +void IndexedDBMessageFilter::DidStartWorkerRunLoop( |
| + const WebWorkerRunLoop& run_loop) { |
| + DCHECK(!tls_worker_run_loop_.Get()); |
| + base::AutoLock locker(run_loops_lock_); |
| + std::pair<LoopSet::iterator, bool> result = run_loops_.insert(run_loop); |
| + DCHECK(result.second); |
| + // We're storing WebWorkerRunLoop in the set, which doesn't allow |
| + // modification through its iterators so as not to invalidate the uniqueness |
| + // constraint on the set. But we've overloaded the comparison operators on |
| + // WebWorkerRunLoop to ignore the non-const state. |
| + WebWorkerRunLoop& a = const_cast<WebWorkerRunLoop&>(*result.first); |
| + tls_worker_run_loop_.Set(&a); |
| +} |
| + |
| +void IndexedDBMessageFilter::DidStopWorkerRunLoop( |
| + const WebWorkerRunLoop& run_loop) { |
| + DCHECK(Contains(run_loop)); |
| + base::AutoLock locker(run_loops_lock_); |
| + run_loops_.erase(run_loop); |
| + |
| + DCHECK(tls_worker_run_loop_.Get()); |
| + tls_worker_run_loop_.Set(NULL); |
|
michaeln
2011/11/30 21:48:14
Looks like there can tbe other instances of WebWor
|
| +} |
| + |
| +WebKit::WebWorkerRunLoop* IndexedDBMessageFilter::current() { |
| + return tls_worker_run_loop_.Get(); |
| +} |
| + |
| +bool IndexedDBMessageFilter::Contains(const WebWorkerRunLoop& run_loop) { |
| + base::AutoLock locker(run_loops_lock_); |
| + LoopSet::iterator iter = run_loops_.find(run_loop); |
| + return iter != run_loops_.end(); |
| +} |
| + |
| +int IndexedDBMessageFilter::GetUniqueID() { |
| + base::AutoLock locker(id_lock_); |
| + int id = ++unique_id_; |
| + if (current()) { |
| + base::AutoLock map_locker(map_lock_); |
| + id_to_run_loop_[id] = current(); |
| + } |
| + return id; |
| +} |
| + |
| +IndexedDBMessageFilter::~IndexedDBMessageFilter() { |
| + // This is never called. |
| + DCHECK_EQ(run_loops_.size(), 0UL); |
| +} |
| + |
| +bool IndexedDBMessageFilter::OnMessageReceived(const IPC::Message& msg) { |
| + bool handled = true; |
| + IPC_BEGIN_MESSAGE_MAP(IndexedDBMessageFilter, msg) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBCursor, |
| + OnSuccessOpenCursor) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorContinue, |
| + OnSuccessCursorContinue) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBDatabase, |
| + OnSuccessIDBDatabase) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIndexedDBKey, |
| + OnSuccessIndexedDBKey) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBTransaction, |
| + OnSuccessIDBTransaction) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessStringList, |
| + OnSuccessStringList) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessSerializedScriptValue, |
| + OnSuccessSerializedScriptValue) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksError, OnError) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksBlocked, OnBlocked) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_TransactionCallbacksAbort, OnAbort) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_TransactionCallbacksComplete, OnComplete) |
| + IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksVersionChange, |
| + OnVersionChange) |
| + IPC_MESSAGE_UNHANDLED(handled = false) |
| + IPC_END_MESSAGE_MAP() |
| + return handled; |
| +} |
| + |
| +void IndexedDBMessageFilter::ForwardToMainThread(const IPC::Message& msg) { |
| + main_thread_loop_proxy_->PostTask(FROM_HERE, |
| + base::Bind(&IndexedDBDispatcher::OnMessageReceived, |
| + main_thread_dispatcher_, msg)); |
| +} |
| + |
| +class MsgForwarderTask : public WebKit::WebWorkerRunLoop::Task { |
| + public: |
| + MsgForwarderTask(const IPC::Message& msg, IndexedDBMessageFilter* filter) : |
| + msg_(msg), |
| + filter_(filter) { |
| + } |
| + virtual ~MsgForwarderTask() { } |
| + virtual void Run() { |
| + IndexedDBDispatcher* dispatcher = filter_->thread_specific_idb_dispatcher(); |
| + dispatcher->OnMessageReceived(msg_); |
| + } |
| + private: |
| + const IPC::Message msg_; |
| + IndexedDBMessageFilter* filter_; |
| +}; |
| + |
| +void IndexedDBMessageFilter::ForwardToThread(const IPC::Message& msg, int32 id, |
| + const IDToRunLoop& map) { |
| + IDToRunLoop::const_iterator iter = map.find(id); |
| + if (iter == map.end()) { |
| + ForwardToMainThread(msg); |
|
michaeln
2011/11/30 21:48:14
Do we need a stronger test for whether or not the
dgrogan
2011/11/30 23:25:18
As it stands now these maps aren't cleaned up, so
|
| + return; |
| + } |
| + MsgForwarderTask* task = new MsgForwarderTask(msg, this); |
| + iter->second->postTask(task); |
|
michaeln
2011/11/30 21:48:14
Should this be under the run_loops_lock_? What gua
dgrogan
2011/11/30 23:25:18
map_lock_, but yes. Fixed.
|
| +} |
| + |
| +void IndexedDBMessageFilter::OnSuccessIDBDatabase(const IPC::Message& msg, |
| + int32 response_id, |
| + int32 object_id) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnSuccessIndexedDBKey(const IPC::Message& msg, |
| + int32 response_id, |
| + const IndexedDBKey& key) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnSuccessIDBTransaction(const IPC::Message& msg, |
| + int32 response_id, |
| + int32 object_id) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnSuccessStringList(const IPC::Message& msg, |
| + int32 response_id, const std::vector<string16>& value) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnSuccessSerializedScriptValue( |
| + const IPC::Message& msg, int32 response_id, |
| + const content::SerializedScriptValue& value) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnSuccessOpenCursor(const IPC::Message& msg, |
| + int32 response_id, int32 object_id, const IndexedDBKey& key, |
| + const IndexedDBKey& primaryKey, |
| + const content::SerializedScriptValue& value) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnSuccessCursorContinue(const IPC::Message& msg, |
| + int32 response_id, |
| + int32 cursor_id, |
| + const IndexedDBKey& key, |
| + const IndexedDBKey& primary_key, |
| + const content::SerializedScriptValue& value) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnBlocked(const IPC::Message& msg, |
| + int32 response_id) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnError(const IPC::Message& msg, |
| + int32 response_id, |
| + int code, |
| + const string16& message) { |
| + ForwardToThread(msg, response_id, id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnAbort(const IPC::Message& msg, |
| + int32 transaction_id) { |
| + ForwardToThread(msg, transaction_id, transaction_id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnComplete(const IPC::Message& msg, |
| + int32 transaction_id) { |
| + ForwardToThread(msg, transaction_id, transaction_id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::OnVersionChange(const IPC::Message& msg, |
| + int32 database_id, |
| + const string16& newVersion) { |
| + ForwardToThread(msg, database_id, database_id_to_run_loop_); |
| +} |
| + |
| +IndexedDBDispatcher* IndexedDBMessageFilter::thread_specific_idb_dispatcher() { |
| + WebWorkerRunLoop* current_loop = current(); |
| + |
| + if (current_loop == NULL) { |
| + // If we're not on a worker thread we should be on the main thread. |
| + DCHECK(RenderThreadImpl::current()); |
| + DCHECK(main_thread_dispatcher_.get()); |
| + return main_thread_dispatcher_.get(); |
| + } |
| + DCHECK(Contains(*current_loop)); |
| + base::AutoLock lock(dispatchers_lock_); |
| + LoopToDispatcherMap::iterator iter = dispatchers_.find(current_loop); |
| + if (iter == dispatchers_.end()) { |
| + dispatchers_[current_loop] = new IndexedDBDispatcher(this); |
|
michaeln
2011/11/30 21:48:14
where is this map cleaned up?
dgrogan
2011/11/30 23:25:18
It appears that it isn't. I had intended to clean
|
| + } |
| + return dispatchers_[current_loop]; |
| +} |
| + |
| +void IndexedDBMessageFilter::RemoveForType(int32 id, WebKit::WebIDBCallbacks*) { |
| + RemoveFromMap(id, &id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::RemoveForType( |
| + int32 id, |
| + WebKit::WebIDBDatabaseCallbacks*) { |
| + RemoveFromMap(id, &database_id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::RemoveForType( |
| + int32 id, |
| + WebKit::WebIDBTransactionCallbacks*) { |
| + RemoveFromMap(id, &transaction_id_to_run_loop_); |
| +} |
| + |
| +void IndexedDBMessageFilter::RemoveFromMap(int32 id, IDToRunLoop* map) { |
| + // We don't store ids that are associated with the main thread. |
| + if (!current()) |
| + return; |
| + base::AutoLock map_locker(map_lock_); |
| + int num_erased = map->erase(id); |
| + DCHECK_EQ(num_erased, 1); |
| +} |
| + |
| +void IndexedDBMessageFilter::NotifyAddWithIDForType( |
| + int32 id, WebKit::WebIDBTransactionCallbacks* callbacks) { |
| + if (current()) { |
| + base::AutoLock map_locker(map_lock_); |
| + transaction_id_to_run_loop_[id] = current(); |
| + } |
| +} |
| + |
| +void IndexedDBMessageFilter::NotifyAddWithIDForType(int32 id, |
| + WebKit::WebIDBDatabaseCallbacks* callbacks) { |
| + if (current()) { |
| + base::AutoLock map_locker(map_lock_); |
| + database_id_to_run_loop_[id] = current(); |
| + } |
| +} |