diff options
author | mad@google.com <mad@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-05 18:12:25 +0000 |
---|---|---|
committer | mad@google.com <mad@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-05 18:12:25 +0000 |
commit | 85984172311aa1e16c25046197cce7cb30418318 (patch) | |
tree | 84ea11104aa262c53c413062f61dbe7e3c3e6573 /ceee | |
parent | 8e5cc282d45e58103b7e67c510c1ca09662b6e29 (diff) | |
download | chromium_src-85984172311aa1e16c25046197cce7cb30418318.zip chromium_src-85984172311aa1e16c25046197cce7cb30418318.tar.gz chromium_src-85984172311aa1e16c25046197cce7cb30418318.tar.bz2 |
Relanding of http://src.chromium.org/viewvc/chrome?view=rev&revision=68298...
Make sure we don't keep tab id - handles mapping when a dread^Wthread dies.
TBR=joi
BUG=65153
TEST=Just make sure it builds...
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68315 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ceee')
-rw-r--r-- | ceee/ie/broker/chrome_postman.cc | 12 | ||||
-rw-r--r-- | ceee/ie/broker/chrome_postman.h | 3 | ||||
-rw-r--r-- | ceee/ie/broker/executors_manager.cc | 47 | ||||
-rw-r--r-- | ceee/ie/broker/executors_manager.h | 5 |
4 files changed, 64 insertions, 3 deletions
diff --git a/ceee/ie/broker/chrome_postman.cc b/ceee/ie/broker/chrome_postman.cc index bc44023..9a9562d 100644 --- a/ceee/ie/broker/chrome_postman.cc +++ b/ceee/ie/broker/chrome_postman.cc @@ -6,12 +6,12 @@ #include "ceee/ie/broker/chrome_postman.h" #include "base/string_util.h" +#include "ceee/common/com_utils.h" #include "ceee/ie/broker/api_dispatcher.h" #include "ceee/ie/common/api_registration.h" #include "ceee/ie/common/ceee_module_util.h" #include "chrome/browser/automation/extension_automation_constants.h" #include "chrome/common/url_constants.h" -#include "ceee/common/com_utils.h" namespace ext = extension_automation_constants; @@ -121,6 +121,16 @@ void ChromePostman::PostMessage(BSTR message, BSTR target) { } } +void ChromePostman::QueueApiInvocationThreadTask(Task* task) { + MessageLoop* message_loop = api_worker_thread_.message_loop(); + if (message_loop) { + message_loop->PostTask(FROM_HERE, task); + } else { + LOG(ERROR) << "Trying to queue a task before the API worker thread is" + "completely initialized and ready."; + } +} + void ChromePostman::FireEvent(const char* event_name, const char* event_args) { MessageLoop* message_loop = api_worker_thread_.message_loop(); if (message_loop) { diff --git a/ceee/ie/broker/chrome_postman.h b/ceee/ie/broker/chrome_postman.h index 11c05b8..33d9418 100644 --- a/ceee/ie/broker/chrome_postman.h +++ b/ceee/ie/broker/chrome_postman.h @@ -45,6 +45,9 @@ class ChromePostman // This posts a tasks to the Api Invocation thread to fire the given event. virtual void FireEvent(const char* event_name, const char* event_args); + // This queues a generic tasks to be executed in the Api Invocation thread. + virtual void QueueApiInvocationThreadTask(Task* task); + // This creates both an STA and an MTA threads. We must make sure we only call // Chrome Frame from this STA. And since we can't block Chrome Frame we use // the MTA thread to executes API Invocation we receive from Chrome Frame. diff --git a/ceee/ie/broker/executors_manager.cc b/ceee/ie/broker/executors_manager.cc index 84d3c37..a221eb6 100644 --- a/ceee/ie/broker/executors_manager.cc +++ b/ceee/ie/broker/executors_manager.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "ceee/ie/broker/broker_module_util.h" +#include "ceee/ie/broker/chrome_postman.h" #include "ceee/ie/broker/common_api_module.h" #include "ceee/common/com_utils.h" @@ -192,6 +193,7 @@ HRESULT ExecutorsManager::RegisterWindowExecutor(ThreadId thread_id, HRESULT ExecutorsManager::GetExecutor(ThreadId thread_id, HWND window, REFIID riid, void** executor) { + VLOG(1) << "Thread: " << thread_id << ", window: " << window; DCHECK(executor != NULL); // We may need to wait for either a currently pending // or own newly created registration of a new executor. @@ -410,9 +412,11 @@ void ExecutorsManager::DeleteTabHandle(HWND handle) { AutoLock lock(lock_); { HandleMap::iterator handle_it = handle_map_.find(handle); - DCHECK(handle_map_.end() != handle_it); + // Don't DCHECK, we may be called more than once, but it's fine, + // we just ignore subsequent calls. if (handle_map_.end() != handle_it) { TabIdMap::iterator tab_id_it = tab_id_map_.find(handle_it->second); + // But if we have it in one map, we must have it in the reverse map. DCHECK(tab_id_map_.end() != tab_id_it); if (tab_id_map_.end() != tab_id_it) { #ifdef DEBUG @@ -474,6 +478,31 @@ void ExecutorsManager::DeleteTabHandle(HWND handle) { windows_events_funnel().OnRemoved(frame_window); } +// This is for using CleanupMapsForThread() into a runnable object without +// the need to AddRef/Release the ExecutorsManager which is a Singleton. +DISABLE_RUNNABLE_METHOD_REFCOUNT(ExecutorsManager); + +void ExecutorsManager::CleanupMapsForThread(DWORD thread_id) { + // We collect the tab handles to remove so that we can do it outside of lock. + // This is because 1) it's not trivial to do it while we loop through the map, + // since there are multiple maps to deal with and the DeleteHandle takes care + // of that for us, and 2) we can't call DeleteHandle from within a lock. + std::vector<HWND> tab_handles_to_remove; + { + AutoLock lock(lock_); + HandleMap::iterator handle_it = handle_map_.begin(); + for (; handle_it != handle_map_.end(); ++ handle_it) { + if (::GetWindowThreadProcessId(handle_it->first, NULL) == thread_id) + tab_handles_to_remove.push_back(handle_it->first); + } + } // AutoLock end + + std::vector<HWND>::iterator tab_handle_it = tab_handles_to_remove.begin(); + for (; tab_handle_it != tab_handles_to_remove.end(); ++tab_handle_it) { + DeleteTabHandle(*tab_handle_it); + } +} + bool ExecutorsManager::IsTabIdValid(int tab_id) { AutoLock lock(lock_); TabIdMap::const_iterator it = tab_id_map_.find(tab_id); @@ -607,7 +636,21 @@ DWORD ExecutorsManager::ThreadProc(LPVOID parameter) { } else if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + num_threads) { // One of our threads have died, cleanup time. - me->RemoveExecutor(thread_ids[result - WAIT_OBJECT_0]); + DWORD thread_id = thread_ids[result - WAIT_OBJECT_0]; + VLOG(1) << "Thread: " << thread_id << " is dying on us!"; + me->RemoveExecutor(thread_id); + // We must asynchronously post this change in case there are pending + // asynchronous notifications (e.g., tabs.onRemoved) that would still + // need the handle to tab id mapping. + // NOTE: No need to worry about the lifespan of the executors manager + // referred by the me variable since it's a singleton released at exit. + ChromePostman* single_instance = ChromePostman::GetInstance(); + // This is not intialized in unittests yet. + if (single_instance) { + single_instance->QueueApiInvocationThreadTask( + NewRunnableMethod(me, &ExecutorsManager::CleanupMapsForThread, + thread_id)); + } } else if (result == WAIT_OBJECT_0 + num_threads + kTerminationHandleIndexOffset) { // we are being terminated, break the cycle. diff --git a/ceee/ie/broker/executors_manager.h b/ceee/ie/broker/executors_manager.h index a51e2da..48a15f9 100644 --- a/ceee/ie/broker/executors_manager.h +++ b/ceee/ie/broker/executors_manager.h @@ -16,6 +16,7 @@ #include "base/lock.h" #include "base/singleton.h" +#include "base/task.h" #include "ceee/common/window_utils.h" #include "ceee/ie/broker/window_events_funnel.h" @@ -120,6 +121,10 @@ class ExecutorsManager { // Unregister the HWND and its corresponding tab ID and tool band tab ID. virtual void DeleteTabHandle(HWND handle); + // Cleans up the maps from all handles that would be associated to the given + // thread id. + virtual void CleanupMapsForThread(DWORD thread_id); + // Traits for Singleton<ExecutorsManager> so that we can pass an argument // to the constructor. struct SingletonTraits : public DefaultSingletonTraits<ExecutorsManager> { |