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 |