| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 // ExecutorsManager implementation. | 5 // ExecutorsManager implementation. |
| 6 | 6 |
| 7 #include "ceee/ie/broker/executors_manager.h" | 7 #include "ceee/ie/broker/executors_manager.h" |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "ceee/ie/broker/broker_module_util.h" | 10 #include "ceee/ie/broker/broker_module_util.h" |
| 11 #include "ceee/ie/broker/chrome_postman.h" | |
| 12 #include "ceee/ie/broker/common_api_module.h" | 11 #include "ceee/ie/broker/common_api_module.h" |
| 13 #include "ceee/common/com_utils.h" | 12 #include "ceee/common/com_utils.h" |
| 14 | 13 |
| 15 namespace { | 14 namespace { |
| 16 | 15 |
| 17 // The timeout we set before accepting a failure when we wait for events. | 16 // The timeout we set before accepting a failure when we wait for events. |
| 18 const DWORD kTimeOut = 20000; | 17 const DWORD kTimeOut = 20000; |
| 19 | 18 |
| 20 // Utility class to ensure the setting of an event before we exit a method. | 19 // Utility class to ensure the setting of an event before we exit a method. |
| 21 class AutoSetEvent { | 20 class AutoSetEvent { |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 } | 185 } |
| 187 | 186 |
| 188 // Update the list of handles that our thread is waiting on. | 187 // Update the list of handles that our thread is waiting on. |
| 189 BOOL success = ::SetEvent(update_threads_list_gate_); | 188 BOOL success = ::SetEvent(update_threads_list_gate_); |
| 190 DCHECK(success); | 189 DCHECK(success); |
| 191 return S_OK; | 190 return S_OK; |
| 192 } | 191 } |
| 193 | 192 |
| 194 HRESULT ExecutorsManager::GetExecutor(ThreadId thread_id, HWND window, | 193 HRESULT ExecutorsManager::GetExecutor(ThreadId thread_id, HWND window, |
| 195 REFIID riid, void** executor) { | 194 REFIID riid, void** executor) { |
| 196 VLOG(1) << "Thread: " << thread_id << ", window: " << window; | |
| 197 DCHECK(executor != NULL); | 195 DCHECK(executor != NULL); |
| 198 // We may need to wait for either a currently pending | 196 // We may need to wait for either a currently pending |
| 199 // or own newly created registration of a new executor. | 197 // or own newly created registration of a new executor. |
| 200 CHandle executor_registration_gate; | 198 CHandle executor_registration_gate; |
| 201 | 199 |
| 202 // We need to remember if we must create a new one or not. | 200 // We need to remember if we must create a new one or not. |
| 203 // But we must create the executor creator outside of the lock. | 201 // But we must create the executor creator outside of the lock. |
| 204 bool create_executor = false; | 202 bool create_executor = false; |
| 205 { | 203 { |
| 206 AutoLock lock(lock_); | 204 AutoLock lock(lock_); |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 HWND frame_window = window_utils::GetTopLevelParent(handle); | 403 HWND frame_window = window_utils::GetTopLevelParent(handle); |
| 406 // There are cases where it's too late to get the parent, | 404 // There are cases where it's too late to get the parent, |
| 407 // so we will need to dig for it deeper later. | 405 // so we will need to dig for it deeper later. |
| 408 if (!common_api::CommonApiResult::IsIeFrameClass(frame_window)) | 406 if (!common_api::CommonApiResult::IsIeFrameClass(frame_window)) |
| 409 frame_window = NULL; | 407 frame_window = NULL; |
| 410 | 408 |
| 411 bool send_on_removed = false; | 409 bool send_on_removed = false; |
| 412 AutoLock lock(lock_); | 410 AutoLock lock(lock_); |
| 413 { | 411 { |
| 414 HandleMap::iterator handle_it = handle_map_.find(handle); | 412 HandleMap::iterator handle_it = handle_map_.find(handle); |
| 415 // Don't DCHECK, we may be called more than once, but it's fine, | 413 DCHECK(handle_map_.end() != handle_it); |
| 416 // we just ignore subsequent calls. | |
| 417 if (handle_map_.end() != handle_it) { | 414 if (handle_map_.end() != handle_it) { |
| 418 TabIdMap::iterator tab_id_it = tab_id_map_.find(handle_it->second); | 415 TabIdMap::iterator tab_id_it = tab_id_map_.find(handle_it->second); |
| 419 // But if we have it in one map, we must have it in the reverse map. | |
| 420 DCHECK(tab_id_map_.end() != tab_id_it); | 416 DCHECK(tab_id_map_.end() != tab_id_it); |
| 421 if (tab_id_map_.end() != tab_id_it) { | 417 if (tab_id_map_.end() != tab_id_it) { |
| 422 #ifdef DEBUG | 418 #ifdef DEBUG |
| 423 tab_id_map_[handle_it->second] = | 419 tab_id_map_[handle_it->second] = |
| 424 reinterpret_cast<HWND>(INVALID_HANDLE_VALUE); | 420 reinterpret_cast<HWND>(INVALID_HANDLE_VALUE); |
| 425 handle_map_[handle] = kInvalidChromeSessionId; | 421 handle_map_[handle] = kInvalidChromeSessionId; |
| 426 #else | 422 #else |
| 427 tab_id_map_.erase(handle_it->second); | 423 tab_id_map_.erase(handle_it->second); |
| 428 handle_map_.erase(handle); | 424 handle_map_.erase(handle); |
| 429 #endif // DEBUG | 425 #endif // DEBUG |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 frame_window_families_.erase(frame_window); | 467 frame_window_families_.erase(frame_window); |
| 472 send_on_removed = true; | 468 send_on_removed = true; |
| 473 } | 469 } |
| 474 } // End of lock | 470 } // End of lock |
| 475 | 471 |
| 476 // Safer to send notifications outside of our lock. | 472 // Safer to send notifications outside of our lock. |
| 477 if (send_on_removed) | 473 if (send_on_removed) |
| 478 windows_events_funnel().OnRemoved(frame_window); | 474 windows_events_funnel().OnRemoved(frame_window); |
| 479 } | 475 } |
| 480 | 476 |
| 481 // This is for using CleanupMapsForThread() into a runnable object without | |
| 482 // the need to AddRef/Release the ExecutorsManager which is a Singleton. | |
| 483 DISABLE_RUNNABLE_METHOD_REFCOUNT(ExecutorsManager); | |
| 484 | |
| 485 void ExecutorsManager::CleanupMapsForThread(DWORD thread_id) { | |
| 486 // We collect the tab handles to remove so that we can do it outside of lock. | |
| 487 // This is because 1) it's not trivial to do it while we loop through the map, | |
| 488 // since there are multiple maps to deal with and the DeleteHandle takes care | |
| 489 // of that for us, and 2) we can't call DeleteHandle from within a lock. | |
| 490 std::vector<HWND> tab_handles_to_remove; | |
| 491 { | |
| 492 AutoLock lock(lock_); | |
| 493 HandleMap::iterator handle_it = handle_map_.begin(); | |
| 494 for (; handle_it != handle_map_.end(); ++ handle_it) { | |
| 495 if (::GetWindowThreadProcessId(handle_it->first, NULL) == thread_id) | |
| 496 tab_handles_to_remove.push_back(handle_it->first); | |
| 497 } | |
| 498 } // AutoLock end | |
| 499 | |
| 500 std::vector<HWND>::iterator tab_handle_it = tab_handles_to_remove.begin(); | |
| 501 for (; tab_handle_it != tab_handles_to_remove.end(); ++tab_handle_it) { | |
| 502 DeleteTabHandle(*tab_handle_it); | |
| 503 } | |
| 504 } | |
| 505 | |
| 506 bool ExecutorsManager::IsTabIdValid(int tab_id) { | 477 bool ExecutorsManager::IsTabIdValid(int tab_id) { |
| 507 AutoLock lock(lock_); | 478 AutoLock lock(lock_); |
| 508 TabIdMap::const_iterator it = tab_id_map_.find(tab_id); | 479 TabIdMap::const_iterator it = tab_id_map_.find(tab_id); |
| 509 #ifdef DEBUG | 480 #ifdef DEBUG |
| 510 return it != tab_id_map_.end() && it->second != INVALID_HANDLE_VALUE; | 481 return it != tab_id_map_.end() && it->second != INVALID_HANDLE_VALUE; |
| 511 #else | 482 #else |
| 512 return it != tab_id_map_.end(); | 483 return it != tab_id_map_.end(); |
| 513 #endif | 484 #endif |
| 514 } | 485 } |
| 515 | 486 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 size_t num_handles = num_threads + kExtraHandles; | 600 size_t num_handles = num_threads + kExtraHandles; |
| 630 DWORD result = me->WaitForMultipleObjects(num_handles, handles, FALSE, | 601 DWORD result = me->WaitForMultipleObjects(num_handles, handles, FALSE, |
| 631 INFINITE); | 602 INFINITE); |
| 632 if (result == WAIT_OBJECT_0 + num_threads + | 603 if (result == WAIT_OBJECT_0 + num_threads + |
| 633 kUpdateHandleIndexOffset) { | 604 kUpdateHandleIndexOffset) { |
| 634 // We got a new thread added, | 605 // We got a new thread added, |
| 635 // simply let the loop turn to add it to our watch list. | 606 // simply let the loop turn to add it to our watch list. |
| 636 } else if (result >= WAIT_OBJECT_0 && | 607 } else if (result >= WAIT_OBJECT_0 && |
| 637 result < WAIT_OBJECT_0 + num_threads) { | 608 result < WAIT_OBJECT_0 + num_threads) { |
| 638 // One of our threads have died, cleanup time. | 609 // One of our threads have died, cleanup time. |
| 639 DWORD thread_id = thread_ids[result - WAIT_OBJECT_0]; | 610 me->RemoveExecutor(thread_ids[result - WAIT_OBJECT_0]); |
| 640 VLOG(1) << "Thread: " << thread_id << " is dying on us!"; | |
| 641 me->RemoveExecutor(thread_id); | |
| 642 // We must asynchronously post this change in case there are pending | |
| 643 // asynchronous notifications (e.g., tabs.onRemoved) that would still | |
| 644 // need the handle to tab id mapping. | |
| 645 // NOTE: No need to worry about the lifespan of the executors manager | |
| 646 // referred by the me variable since it's a singleton released at exit. | |
| 647 ChromePostman* single_instance = ChromePostman::GetInstance(); | |
| 648 // This is not intialized in unittests yet. | |
| 649 if (single_instance) { | |
| 650 single_instance->QueueApiInvocationThreadTask( | |
| 651 NewRunnableMethod(me, &ExecutorsManager::CleanupMapsForThread, | |
| 652 thread_id)); | |
| 653 } | |
| 654 } else if (result == WAIT_OBJECT_0 + num_threads + | 611 } else if (result == WAIT_OBJECT_0 + num_threads + |
| 655 kTerminationHandleIndexOffset) { | 612 kTerminationHandleIndexOffset) { |
| 656 // we are being terminated, break the cycle. | 613 // we are being terminated, break the cycle. |
| 657 break; | 614 break; |
| 658 } else { | 615 } else { |
| 659 DCHECK(result == WAIT_FAILED); | 616 DCHECK(result == WAIT_FAILED); |
| 660 LOG(ERROR) << "ExecutorsManager::ThreadProc " << com::LogWe(); | 617 LOG(ERROR) << "ExecutorsManager::ThreadProc " << com::LogWe(); |
| 661 break; | 618 break; |
| 662 } | 619 } |
| 663 } | 620 } |
| 664 // Merci... Bonsoir... | 621 // Merci... Bonsoir... |
| 665 ::CoUninitialize(); | 622 ::CoUninitialize(); |
| 666 return 1; | 623 return 1; |
| 667 } | 624 } |
| OLD | NEW |