Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(391)

Side by Side Diff: remoting/client/plugin/chromoting_instance.cc

Issue 10440107: Replace ScopedThreadProxy with MessageLoopProxy & WeakPtrs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Use correct TaskRunner reference, and copy instance reference in lock. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/client/plugin/chromoting_instance.h ('k') | remoting/host/host_user_interface.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 #include "remoting/client/plugin/chromoting_instance.h" 5 #include "remoting/client/plugin/chromoting_instance.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 return "INCOMPATIBLE_PROTOCOL"; 84 return "INCOMPATIBLE_PROTOCOL";
85 case ChromotingInstance::ERROR_NETWORK_FAILURE: 85 case ChromotingInstance::ERROR_NETWORK_FAILURE:
86 return "NETWORK_FAILURE"; 86 return "NETWORK_FAILURE";
87 case ChromotingInstance::ERROR_HOST_OVERLOAD: 87 case ChromotingInstance::ERROR_HOST_OVERLOAD:
88 return "HOST_OVERLOAD"; 88 return "HOST_OVERLOAD";
89 } 89 }
90 NOTREACHED(); 90 NOTREACHED();
91 return ""; 91 return "";
92 } 92 }
93 93
94 } // namespace
95
96 // This flag blocks LOGs to the UI if we're already in the middle of logging 94 // This flag blocks LOGs to the UI if we're already in the middle of logging
97 // to the UI. This prevents a potential infinite loop if we encounter an error 95 // to the UI. This prevents a potential infinite loop if we encounter an error
98 // while sending the log message to the UI. 96 // while sending the log message to the UI.
99 static bool g_logging_to_plugin = false; 97 bool g_logging_to_plugin = false;
100 static bool g_has_logging_instance = false; 98 bool g_has_logging_instance = false;
101 static ChromotingInstance* g_logging_instance = NULL; 99 base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner> >::Leaky
102 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; 100 g_logging_task_runner = LAZY_INSTANCE_INITIALIZER;
101 base::LazyInstance<base::WeakPtr<ChromotingInstance> >::Leaky
102 g_logging_instance = LAZY_INSTANCE_INITIALIZER;
103 base::LazyInstance<base::Lock>::Leaky
104 g_logging_lock = LAZY_INSTANCE_INITIALIZER;
105 logging::LogMessageHandlerFunction g_logging_old_handler = NULL;
103 106
104 static base::LazyInstance<base::Lock>::Leaky 107 } // namespace
105 g_logging_lock = LAZY_INSTANCE_INITIALIZER;
106 108
107 // String sent in the "hello" message to the plugin to describe features. 109 // String sent in the "hello" message to the plugin to describe features.
108 const char ChromotingInstance::kApiFeatures[] = 110 const char ChromotingInstance::kApiFeatures[] =
109 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " 111 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey "
110 "notifyClientDimensions pauseVideo"; 112 "notifyClientDimensions pauseVideo";
111 113
112 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str, 114 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str,
113 ClientConfig* config) { 115 ClientConfig* config) {
114 std::vector<std::string> auth_methods; 116 std::vector<std::string> auth_methods;
115 base::SplitString(auth_methods_str, ',', &auth_methods); 117 base::SplitString(auth_methods_str, ',', &auth_methods);
(...skipping 11 matching lines...) Expand all
127 129
128 return true; 130 return true;
129 } 131 }
130 132
131 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) 133 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance)
132 : pp::Instance(pp_instance), 134 : pp::Instance(pp_instance),
133 initialized_(false), 135 initialized_(false),
134 plugin_message_loop_( 136 plugin_message_loop_(
135 new PluginMessageLoopProxy(&plugin_thread_delegate_)), 137 new PluginMessageLoopProxy(&plugin_thread_delegate_)),
136 context_(plugin_message_loop_), 138 context_(plugin_message_loop_),
137 thread_proxy_(new ScopedThreadProxy(plugin_message_loop_)) { 139 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
138 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); 140 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL);
139 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); 141 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
140 142
141 // Resister this instance to handle debug log messsages. 143 // Resister this instance to handle debug log messsages.
142 RegisterLoggingInstance(); 144 RegisterLoggingInstance();
143 145
144 // Send hello message. 146 // Send hello message.
145 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 147 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
146 data->SetInteger("apiVersion", kApiVersion); 148 data->SetInteger("apiVersion", kApiVersion);
147 data->SetString("apiFeatures", kApiFeatures); 149 data->SetString("apiFeatures", kApiFeatures);
148 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); 150 data->SetInteger("apiMinVersion", kApiMinMessagingVersion);
149 PostChromotingMessage("hello", data.Pass()); 151 PostChromotingMessage("hello", data.Pass());
150 } 152 }
151 153
152 ChromotingInstance::~ChromotingInstance() { 154 ChromotingInstance::~ChromotingInstance() {
153 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); 155 DCHECK(plugin_message_loop_->BelongsToCurrentThread());
154 156
155 // Detach the log proxy so we don't log anything else to the UI.
156 // This needs to be done before the instance is unregistered for logging.
157 thread_proxy_->Detach();
158
159 // Unregister this instance so that debug log messages will no longer be sent 157 // Unregister this instance so that debug log messages will no longer be sent
160 // to it. This will stop all logging in all Chromoting instances. 158 // to it. This will stop all logging in all Chromoting instances.
161 UnregisterLoggingInstance(); 159 UnregisterLoggingInstance();
162 160
163 if (client_.get()) { 161 if (client_.get()) {
164 base::WaitableEvent done_event(true, false); 162 base::WaitableEvent done_event(true, false);
165 client_->Stop(base::Bind(&base::WaitableEvent::Signal, 163 client_->Stop(base::Bind(&base::WaitableEvent::Signal,
166 base::Unretained(&done_event))); 164 base::Unretained(&done_event)));
167 done_event.Wait(); 165 done_event.Wait();
168 } 166 }
169 167
170 // Stopping the context shuts down all chromoting threads. 168 // Stopping the context shuts down all chromoting threads.
171 context_.Stop(); 169 context_.Stop();
172 170
173 // Delete |thread_proxy_| before we detach |plugin_message_loop_|, 171 // Ensure that nothing touches the plugin thread delegate after this point.
174 // otherwise ScopedThreadProxy may DCHECK when being destroyed.
175 thread_proxy_.reset();
176
177 plugin_message_loop_->Detach(); 172 plugin_message_loop_->Detach();
178 } 173 }
179 174
180 bool ChromotingInstance::Init(uint32_t argc, 175 bool ChromotingInstance::Init(uint32_t argc,
181 const char* argn[], 176 const char* argn[],
182 const char* argv[]) { 177 const char* argv[]) {
183 CHECK(!initialized_); 178 CHECK(!initialized_);
184 initialized_ = true; 179 initialized_ = true;
185 180
186 VLOG(1) << "Started ChromotingInstance::Init"; 181 VLOG(1) << "Started ChromotingInstance::Init";
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
618 logging::SetLogMessageHandler(&LogToUI); 613 logging::SetLogMessageHandler(&LogToUI);
619 } 614 }
620 615
621 void ChromotingInstance::RegisterLoggingInstance() { 616 void ChromotingInstance::RegisterLoggingInstance() {
622 base::AutoLock lock(g_logging_lock.Get()); 617 base::AutoLock lock(g_logging_lock.Get());
623 618
624 // Register this instance as the one that will handle all logging calls 619 // Register this instance as the one that will handle all logging calls
625 // and display them to the user. 620 // and display them to the user.
626 // If multiple plugins are run, then the last one registered will handle all 621 // If multiple plugins are run, then the last one registered will handle all
627 // logging for all instances. 622 // logging for all instances.
628 g_logging_instance = this; 623 g_logging_instance.Get() = weak_factory_.GetWeakPtr();
624 g_logging_task_runner.Get() = plugin_message_loop_;
629 g_has_logging_instance = true; 625 g_has_logging_instance = true;
630 } 626 }
631 627
632 void ChromotingInstance::UnregisterLoggingInstance() { 628 void ChromotingInstance::UnregisterLoggingInstance() {
633 base::AutoLock lock(g_logging_lock.Get()); 629 base::AutoLock lock(g_logging_lock.Get());
634 630
635 // Don't unregister unless we're the currently registered instance. 631 // Don't unregister unless we're the currently registered instance.
636 if (this != g_logging_instance) 632 if (this != g_logging_instance.Get().get())
637 return; 633 return;
638 634
639 // Unregister this instance for logging. 635 // Unregister this instance for logging.
640 g_has_logging_instance = false; 636 g_has_logging_instance = false;
641 g_logging_instance = NULL; 637 g_logging_instance.Get().reset();
638 g_logging_task_runner.Get() = NULL;
642 639
643 VLOG(1) << "Unregistering global log handler"; 640 VLOG(1) << "Unregistering global log handler";
644 } 641 }
645 642
646 // static 643 // static
647 bool ChromotingInstance::LogToUI(int severity, const char* file, int line, 644 bool ChromotingInstance::LogToUI(int severity, const char* file, int line,
648 size_t message_start, 645 size_t message_start,
649 const std::string& str) { 646 const std::string& str) {
650 // Note that we're reading |g_has_logging_instance| outside of a lock. 647 // Note that we're reading |g_has_logging_instance| outside of a lock.
651 // This lockless read is done so that we don't needlessly slow down global 648 // This lockless read is done so that we don't needlessly slow down global
652 // logging with a lock for each log message. 649 // logging with a lock for each log message.
653 // 650 //
654 // This lockless read is safe because: 651 // This lockless read is safe because:
655 // 652 //
656 // Misreading a false value (when it should be true) means that we'll simply 653 // Misreading a false value (when it should be true) means that we'll simply
657 // skip processing a few log messages. 654 // skip processing a few log messages.
658 // 655 //
659 // Misreading a true value (when it should be false) means that we'll take 656 // Misreading a true value (when it should be false) means that we'll take
660 // the lock and check |g_logging_instance| unnecessarily. This is not 657 // the lock and check |g_logging_instance| unnecessarily. This is not
661 // problematic because we always set |g_logging_instance| inside a lock. 658 // problematic because we always set |g_logging_instance| inside a lock.
662 if (g_has_logging_instance) { 659 if (g_has_logging_instance) {
663 // Do not LOG anything while holding this lock or else the code will 660 scoped_refptr<base::SingleThreadTaskRunner> logging_task_runner;
664 // deadlock while trying to re-get the lock we're already in. 661 base::WeakPtr<ChromotingInstance> logging_instance;
665 base::AutoLock lock(g_logging_lock.Get()); 662
666 if (g_logging_instance && 663 {
667 // If |g_logging_to_plugin| is set and we're on the logging thread, then 664 base::AutoLock lock(g_logging_lock.Get());
668 // this LOG message came from handling a previous LOG message and we 665 // If we're on the logging thread and |g_logging_to_plugin| is set then
669 // should skip it to avoid an infinite loop of LOG messages. 666 // this LOG message came from handling a previous LOG message and we
670 // We don't have a lock around |g_in_processtoui|, but that's OK since 667 // should skip it to avoid an infinite loop of LOG messages.
671 // the value is only read/written on the logging thread. 668 if (!g_logging_task_runner.Get()->BelongsToCurrentThread() ||
672 (!g_logging_instance->plugin_message_loop_->BelongsToCurrentThread() || 669 !g_logging_to_plugin) {
673 !g_logging_to_plugin)) { 670 logging_task_runner = g_logging_task_runner.Get();
671 logging_instance = g_logging_instance.Get();
672 }
673 }
674
675 if (logging_task_runner.get()) {
674 std::string message = remoting::GetTimestampString(); 676 std::string message = remoting::GetTimestampString();
675 message += (str.c_str() + message_start); 677 message += (str.c_str() + message_start);
676 // |thread_proxy_| is safe to use here because we detach it before 678
677 // tearing down the |g_logging_instance|. 679 logging_task_runner->PostTask(
678 g_logging_instance->thread_proxy_->PostTask(
679 FROM_HERE, base::Bind(&ChromotingInstance::ProcessLogToUI, 680 FROM_HERE, base::Bind(&ChromotingInstance::ProcessLogToUI,
680 base::Unretained(g_logging_instance), message)); 681 logging_instance, message));
681 } 682 }
682 } 683 }
683 684
684 if (g_logging_old_handler) 685 if (g_logging_old_handler)
685 return (g_logging_old_handler)(severity, file, line, message_start, str); 686 return (g_logging_old_handler)(severity, file, line, message_start, str);
686 return false; 687 return false;
687 } 688 }
688 689
689 void ChromotingInstance::ProcessLogToUI(const std::string& message) { 690 void ChromotingInstance::ProcessLogToUI(const std::string& message) {
690 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); 691 DCHECK(plugin_message_loop_->BelongsToCurrentThread());
691 692
692 // This flag (which is set only here) is used to prevent LogToUI from posting 693 // This flag (which is set only here) is used to prevent LogToUI from posting
693 // new tasks while we're in the middle of servicing a LOG call. This can 694 // new tasks while we're in the middle of servicing a LOG call. This can
694 // happen if the call to LogDebugInfo tries to LOG anything. 695 // happen if the call to LogDebugInfo tries to LOG anything.
696 // Since it is read on the plugin thread, we don't need to lock to set it.
695 g_logging_to_plugin = true; 697 g_logging_to_plugin = true;
696 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 698 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
697 data->SetString("message", message); 699 data->SetString("message", message);
698 PostChromotingMessage("logDebugMessage", data.Pass()); 700 PostChromotingMessage("logDebugMessage", data.Pass());
699 g_logging_to_plugin = false; 701 g_logging_to_plugin = false;
700 } 702 }
701 703
702 bool ChromotingInstance::IsConnected() { 704 bool ChromotingInstance::IsConnected() {
703 return host_connection_.get() && 705 return host_connection_.get() &&
704 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); 706 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED);
705 } 707 }
706 708
707 } // namespace remoting 709 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/plugin/chromoting_instance.h ('k') | remoting/host/host_user_interface.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698