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

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: 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/desktop_environment.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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 return "INCOMPATIBLE_PROTOCOL"; 83 return "INCOMPATIBLE_PROTOCOL";
84 case ChromotingInstance::ERROR_NETWORK_FAILURE: 84 case ChromotingInstance::ERROR_NETWORK_FAILURE:
85 return "NETWORK_FAILURE"; 85 return "NETWORK_FAILURE";
86 case ChromotingInstance::ERROR_HOST_OVERLOAD: 86 case ChromotingInstance::ERROR_HOST_OVERLOAD:
87 return "HOST_OVERLOAD"; 87 return "HOST_OVERLOAD";
88 } 88 }
89 NOTREACHED(); 89 NOTREACHED();
90 return ""; 90 return "";
91 } 91 }
92 92
93 } // namespace
94
95 // This flag blocks LOGs to the UI if we're already in the middle of logging 93 // This flag blocks LOGs to the UI if we're already in the middle of logging
96 // to the UI. This prevents a potential infinite loop if we encounter an error 94 // to the UI. This prevents a potential infinite loop if we encounter an error
97 // while sending the log message to the UI. 95 // while sending the log message to the UI.
98 static bool g_logging_to_plugin = false; 96 bool g_logging_to_plugin = false;
99 static bool g_has_logging_instance = false; 97 bool g_has_logging_instance = false;
100 static ChromotingInstance* g_logging_instance = NULL; 98 base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner> >::Leaky
101 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; 99 g_logging_task_runner = LAZY_INSTANCE_INITIALIZER;
100 base::LazyInstance<base::WeakPtr<ChromotingInstance> >::Leaky
101 g_logging_instance = LAZY_INSTANCE_INITIALIZER;
102 base::LazyInstance<base::Lock>::Leaky
103 g_logging_lock = LAZY_INSTANCE_INITIALIZER;
104 logging::LogMessageHandlerFunction g_logging_old_handler = NULL;
102 105
103 static base::LazyInstance<base::Lock>::Leaky 106 } // namespace
104 g_logging_lock = LAZY_INSTANCE_INITIALIZER;
105 107
106 // String sent in the "hello" message to the plugin to describe features. 108 // String sent in the "hello" message to the plugin to describe features.
107 const char ChromotingInstance::kApiFeatures[] = 109 const char ChromotingInstance::kApiFeatures[] =
108 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " 110 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey "
109 "notifyClientDimensions pauseVideo"; 111 "notifyClientDimensions pauseVideo";
110 112
111 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str, 113 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str,
112 ClientConfig* config) { 114 ClientConfig* config) {
113 if (auth_methods_str == "v1_token") { 115 if (auth_methods_str == "v1_token") {
114 config->use_v1_authenticator = true; 116 config->use_v1_authenticator = true;
(...skipping 17 matching lines...) Expand all
132 134
133 return true; 135 return true;
134 } 136 }
135 137
136 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) 138 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance)
137 : pp::InstancePrivate(pp_instance), 139 : pp::InstancePrivate(pp_instance),
138 initialized_(false), 140 initialized_(false),
139 plugin_message_loop_( 141 plugin_message_loop_(
140 new PluginMessageLoopProxy(&plugin_thread_delegate_)), 142 new PluginMessageLoopProxy(&plugin_thread_delegate_)),
141 context_(plugin_message_loop_), 143 context_(plugin_message_loop_),
142 thread_proxy_(new ScopedThreadProxy(plugin_message_loop_)) { 144 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
143 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); 145 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL);
144 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); 146 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
145 147
146 // Resister this instance to handle debug log messsages. 148 // Resister this instance to handle debug log messsages.
147 RegisterLoggingInstance(); 149 RegisterLoggingInstance();
148 150
149 // Send hello message. 151 // Send hello message.
150 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 152 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
151 data->SetInteger("apiVersion", kApiVersion); 153 data->SetInteger("apiVersion", kApiVersion);
152 data->SetString("apiFeatures", kApiFeatures); 154 data->SetString("apiFeatures", kApiFeatures);
153 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); 155 data->SetInteger("apiMinVersion", kApiMinMessagingVersion);
154 PostChromotingMessage("hello", data.Pass()); 156 PostChromotingMessage("hello", data.Pass());
155 } 157 }
156 158
157 ChromotingInstance::~ChromotingInstance() { 159 ChromotingInstance::~ChromotingInstance() {
158 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); 160 DCHECK(plugin_message_loop_->BelongsToCurrentThread());
159 161
160 // Detach the log proxy so we don't log anything else to the UI.
161 // This needs to be done before the instance is unregistered for logging.
162 thread_proxy_->Detach();
163
164 // Unregister this instance so that debug log messages will no longer be sent 162 // Unregister this instance so that debug log messages will no longer be sent
165 // to it. This will stop all logging in all Chromoting instances. 163 // to it. This will stop all logging in all Chromoting instances.
166 UnregisterLoggingInstance(); 164 UnregisterLoggingInstance();
167 165
168 if (client_.get()) { 166 if (client_.get()) {
169 base::WaitableEvent done_event(true, false); 167 base::WaitableEvent done_event(true, false);
170 client_->Stop(base::Bind(&base::WaitableEvent::Signal, 168 client_->Stop(base::Bind(&base::WaitableEvent::Signal,
171 base::Unretained(&done_event))); 169 base::Unretained(&done_event)));
172 done_event.Wait(); 170 done_event.Wait();
173 } 171 }
174 172
175 // Stopping the context shuts down all chromoting threads. 173 // Stopping the context shuts down all chromoting threads.
176 context_.Stop(); 174 context_.Stop();
177 175
178 // Delete |thread_proxy_| before we detach |plugin_message_loop_|, 176 // Ensure that nothing touches the plugin thread delegate after this point.
179 // otherwise ScopedThreadProxy may DCHECK when being destroyed.
180 thread_proxy_.reset();
181
182 plugin_message_loop_->Detach(); 177 plugin_message_loop_->Detach();
183 } 178 }
184 179
185 bool ChromotingInstance::Init(uint32_t argc, 180 bool ChromotingInstance::Init(uint32_t argc,
186 const char* argn[], 181 const char* argn[],
187 const char* argv[]) { 182 const char* argv[]) {
188 CHECK(!initialized_); 183 CHECK(!initialized_);
189 initialized_ = true; 184 initialized_ = true;
190 185
191 VLOG(1) << "Started ChromotingInstance::Init"; 186 VLOG(1) << "Started ChromotingInstance::Init";
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 logging::SetLogMessageHandler(&LogToUI); 602 logging::SetLogMessageHandler(&LogToUI);
608 } 603 }
609 604
610 void ChromotingInstance::RegisterLoggingInstance() { 605 void ChromotingInstance::RegisterLoggingInstance() {
611 base::AutoLock lock(g_logging_lock.Get()); 606 base::AutoLock lock(g_logging_lock.Get());
612 607
613 // Register this instance as the one that will handle all logging calls 608 // Register this instance as the one that will handle all logging calls
614 // and display them to the user. 609 // and display them to the user.
615 // If multiple plugins are run, then the last one registered will handle all 610 // If multiple plugins are run, then the last one registered will handle all
616 // logging for all instances. 611 // logging for all instances.
617 g_logging_instance = this; 612 g_logging_instance.Get() = weak_factory_.GetWeakPtr();
613 g_logging_task_runner.Get() = plugin_message_loop_;
618 g_has_logging_instance = true; 614 g_has_logging_instance = true;
619 } 615 }
620 616
621 void ChromotingInstance::UnregisterLoggingInstance() { 617 void ChromotingInstance::UnregisterLoggingInstance() {
622 base::AutoLock lock(g_logging_lock.Get()); 618 base::AutoLock lock(g_logging_lock.Get());
623 619
624 // Don't unregister unless we're the currently registered instance. 620 // Don't unregister unless we're the currently registered instance.
625 if (this != g_logging_instance) 621 if (this != g_logging_instance.Get().get())
626 return; 622 return;
627 623
628 // Unregister this instance for logging. 624 // Unregister this instance for logging.
629 g_has_logging_instance = false; 625 g_has_logging_instance = false;
630 g_logging_instance = NULL; 626 g_logging_instance.Get().reset();
627 g_logging_task_runner.Get() = NULL;
631 628
632 VLOG(1) << "Unregistering global log handler"; 629 VLOG(1) << "Unregistering global log handler";
633 } 630 }
634 631
635 // static 632 // static
636 bool ChromotingInstance::LogToUI(int severity, const char* file, int line, 633 bool ChromotingInstance::LogToUI(int severity, const char* file, int line,
637 size_t message_start, 634 size_t message_start,
638 const std::string& str) { 635 const std::string& str) {
639 // Note that we're reading |g_has_logging_instance| outside of a lock. 636 // Note that we're reading |g_has_logging_instance| outside of a lock.
640 // This lockless read is done so that we don't needlessly slow down global 637 // This lockless read is done so that we don't needlessly slow down global
641 // logging with a lock for each log message. 638 // logging with a lock for each log message.
642 // 639 //
643 // This lockless read is safe because: 640 // This lockless read is safe because:
644 // 641 //
645 // Misreading a false value (when it should be true) means that we'll simply 642 // Misreading a false value (when it should be true) means that we'll simply
646 // skip processing a few log messages. 643 // skip processing a few log messages.
647 // 644 //
648 // Misreading a true value (when it should be false) means that we'll take 645 // Misreading a true value (when it should be false) means that we'll take
649 // the lock and check |g_logging_instance| unnecessarily. This is not 646 // the lock and check |g_logging_instance| unnecessarily. This is not
650 // problematic because we always set |g_logging_instance| inside a lock. 647 // problematic because we always set |g_logging_instance| inside a lock.
651 if (g_has_logging_instance) { 648 if (g_has_logging_instance) {
652 // Do not LOG anything while holding this lock or else the code will 649 scoped_refptr<base::SingleThreadTaskRunner> logging_task_runner;
653 // deadlock while trying to re-get the lock we're already in. 650
654 base::AutoLock lock(g_logging_lock.Get()); 651 {
655 if (g_logging_instance && 652 base::AutoLock lock(g_logging_lock.Get());
656 // If |g_logging_to_plugin| is set and we're on the logging thread, then 653 // If we're on the logging thread and |g_logging_to_plugin| is set then
657 // this LOG message came from handling a previous LOG message and we 654 // this LOG message came from handling a previous LOG message and we
658 // should skip it to avoid an infinite loop of LOG messages. 655 // should skip it to avoid an infinite loop of LOG messages.
659 // We don't have a lock around |g_in_processtoui|, but that's OK since 656 if (!g_logging_task_runner.Get()->BelongsToCurrentThread() ||
660 // the value is only read/written on the logging thread. 657 !g_logging_to_plugin) {
661 (!g_logging_instance->plugin_message_loop_->BelongsToCurrentThread() || 658 logging_task_runner = g_logging_task_runner.Get();
662 !g_logging_to_plugin)) { 659 }
660 }
661
662 if (logging_task_runner.get()) {
663 std::string message = remoting::GetTimestampString(); 663 std::string message = remoting::GetTimestampString();
664 message += (str.c_str() + message_start); 664 message += (str.c_str() + message_start);
665 // |thread_proxy_| is safe to use here because we detach it before 665
666 // tearing down the |g_logging_instance|. 666 g_logging_task_runner.Get()->PostTask(
Sergey Ulanov 2012/06/02 00:57:45 This should be logging_task_runner instead of g_lo
Wez 2012/06/07 16:28:53 Done.
667 g_logging_instance->thread_proxy_->PostTask(
668 FROM_HERE, base::Bind(&ChromotingInstance::ProcessLogToUI, 667 FROM_HERE, base::Bind(&ChromotingInstance::ProcessLogToUI,
669 base::Unretained(g_logging_instance), message)); 668 g_logging_instance.Get(), message));
Sergey Ulanov 2012/06/02 00:57:45 should we also copy g_logging_instance with g_logg
Wez 2012/06/07 16:28:53 Done.
670 } 669 }
671 } 670 }
672 671
673 if (g_logging_old_handler) 672 if (g_logging_old_handler)
674 return (g_logging_old_handler)(severity, file, line, message_start, str); 673 return (g_logging_old_handler)(severity, file, line, message_start, str);
675 return false; 674 return false;
676 } 675 }
677 676
678 void ChromotingInstance::ProcessLogToUI(const std::string& message) { 677 void ChromotingInstance::ProcessLogToUI(const std::string& message) {
679 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); 678 DCHECK(plugin_message_loop_->BelongsToCurrentThread());
680 679
681 // This flag (which is set only here) is used to prevent LogToUI from posting 680 // This flag (which is set only here) is used to prevent LogToUI from posting
682 // new tasks while we're in the middle of servicing a LOG call. This can 681 // new tasks while we're in the middle of servicing a LOG call. This can
683 // happen if the call to LogDebugInfo tries to LOG anything. 682 // happen if the call to LogDebugInfo tries to LOG anything.
683 // Since it is read on the plugin thread, we don't need to lock to set it.
684 g_logging_to_plugin = true; 684 g_logging_to_plugin = true;
685 ChromotingScriptableObject* scriptable_object = GetScriptableObject(); 685 ChromotingScriptableObject* scriptable_object = GetScriptableObject();
686 if (scriptable_object) { 686 if (scriptable_object) {
687 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 687 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
688 data->SetString("message", message); 688 data->SetString("message", message);
689 PostChromotingMessage("logDebugMessage", data.Pass()); 689 PostChromotingMessage("logDebugMessage", data.Pass());
690 690
691 scriptable_object->LogDebugInfo(message); 691 scriptable_object->LogDebugInfo(message);
692 } 692 }
693 g_logging_to_plugin = false; 693 g_logging_to_plugin = false;
694 } 694 }
695 695
696 bool ChromotingInstance::IsConnected() { 696 bool ChromotingInstance::IsConnected() {
697 return host_connection_.get() && 697 return host_connection_.get() &&
698 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); 698 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED);
699 } 699 }
700 700
701 } // namespace remoting 701 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/plugin/chromoting_instance.h ('k') | remoting/host/desktop_environment.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698