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

Side by Side Diff: ceee/ie/plugin/toolband/toolband_module.cc

Issue 4989002: Firing event to broker without worker thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 1 month 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
OLDNEW
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 // Declaration of ATL module object and DLL exports. 5 // Declaration of ATL module object and DLL exports.
6 6
7 #include "base/at_exit.h" 7 #include "base/at_exit.h"
8 #include "base/atomic_ref_count.h" 8 #include "base/atomic_ref_count.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/logging_win.h" 11 #include "base/logging_win.h"
12 #include "base/thread.h"
13 #include "ceee/common/com_utils.h" 12 #include "ceee/common/com_utils.h"
14 #include "ceee/common/install_utils.h" 13 #include "ceee/common/install_utils.h"
15 #include "ceee/ie/broker/broker_rpc_client.h" 14 #include "ceee/ie/broker/broker_rpc_client.h"
16 #include "ceee/ie/common/ceee_module_util.h" 15 #include "ceee/ie/common/ceee_module_util.h"
17 #include "ceee/ie/plugin/bho/browser_helper_object.h" 16 #include "ceee/ie/plugin/bho/browser_helper_object.h"
18 #include "ceee/ie/plugin/bho/executor.h" 17 #include "ceee/ie/plugin/bho/executor.h"
19 #include "ceee/ie/plugin/toolband/toolband_module_reporting.h" 18 #include "ceee/ie/plugin/toolband/toolband_module_reporting.h"
20 #include "ceee/ie/plugin/toolband/tool_band.h" 19 #include "ceee/ie/plugin/toolband/tool_band.h"
21 #include "ceee/ie/plugin/scripting/script_host.h" 20 #include "ceee/ie/plugin/scripting/script_host.h"
22 #include "ceee/common/windows_constants.h" 21 #include "ceee/common/windows_constants.h"
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 53
55 // Needed to make sure we call Init/Term outside the loader lock. 54 // Needed to make sure we call Init/Term outside the loader lock.
56 HRESULT DllCanUnloadNow(); 55 HRESULT DllCanUnloadNow();
57 HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** object); 56 HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** object);
58 void Init(); 57 void Init();
59 void Term(); 58 void Term();
60 bool module_initialized() const { 59 bool module_initialized() const {
61 return module_initialized_; 60 return module_initialized_;
62 } 61 }
63 62
64 // Fires an event to the broker, so that the call can be made with an 63 // Fires an event to the broker.
65 // instance of a broker proxy that was CoCreated in the worker thread.
66 void FireEventToBroker(const std::string& event_name, 64 void FireEventToBroker(const std::string& event_name,
67 const std::string& event_args); 65 const std::string& event_args);
68 66
69 private: 67 private:
70 // TODO(vitalybuka@google.com): Fire events without this thread.
71 class ComWorkerThread : public base::Thread {
72 public:
73 ComWorkerThread();
74 68
75 // Called just prior to starting the message loop 69 // We only attach broker on first use.
76 virtual void Init(); 70 void EnsureBrokerIsConnected();
77 71
78 // Called just after the message loop ends
79 virtual void CleanUp();
80
81 // Called by FireEventTask so that the broker we instantiate in the
82 // worker thread can be used.
83 void FireEventToBroker(BSTR event_name, BSTR event_args);
84 protected:
85 BrokerRpcClient broker_rpc_;
86 };
87
88 class FireEventTask : public Task {
89 public:
90 FireEventTask(ComWorkerThread* worker_thread,
91 const std::string& event_name,
92 const std::string& event_args)
93 : worker_thread_(worker_thread),
94 event_name_(event_name.c_str()),
95 event_args_(event_args.c_str()) {
96 }
97 virtual void Run() {
98 worker_thread_->FireEventToBroker(event_name_, event_args_);
99 }
100 private:
101 ComWorkerThread* worker_thread_;
102 CComBSTR event_name_;
103 CComBSTR event_args_;
104 };
105 // We only start the thread on first use. If we would start it on
106 // initialization, when our DLL is loaded into the broker process,
107 // it would try to start this thread which tries to CoCreate a Broker
108 // and this could cause a complex deadlock...
109 void EnsureThreadStarted();
110
111 // We use a pointer so that we can make sure we only destroy the object
112 // when the thread is properly stopped. Otherwise, we would get a DCHECK
113 // if the thread is killed before we get to Stop it when DllCanUnloadNow
114 // returns S_OK, which happens when the application quits with live objects,
115 // this causes the destructor to DCHECK.
116 ComWorkerThread* worker_thread_;
117 base::AtExitManager at_exit_; 72 base::AtExitManager at_exit_;
118 bool module_initialized_; 73 bool module_initialized_;
119 bool crash_reporting_initialized_; 74 bool crash_reporting_initialized_;
120 75
121 int worker_thread_ref_count_; 76 int broker_ref_count_;
122 77
123 friend void ceee_module_util::AddRefModuleWorkerThread(); 78 BrokerRpcClient broker_rpc_client_;
124 friend void ceee_module_util::ReleaseModuleWorkerThread();
125 79
126 void IncThreadRefCount(); 80 friend void ceee_module_util::AddRefBroker();
127 void DecThreadRefCount(); 81 friend void ceee_module_util::ReleaseBroker();
82
83 void IncBrokerRefCount();
84 void DecBrokerRefCount();
128 }; 85 };
129 86
130 ToolbandModule::ToolbandModule() 87 ToolbandModule::ToolbandModule()
131 : crash_reporting_initialized_(false), 88 : crash_reporting_initialized_(false),
132 module_initialized_(false), 89 module_initialized_(false) {
133 worker_thread_(NULL) {
134 wchar_t logfile_path[MAX_PATH]; 90 wchar_t logfile_path[MAX_PATH];
135 DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path); 91 DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path);
136 ::PathAppend(logfile_path, kLogFileName); 92 ::PathAppend(logfile_path, kLogFileName);
137 93
138 // It seems we're obliged to initialize the current command line 94 // It seems we're obliged to initialize the current command line
139 // before initializing logging. This feels a little strange for 95 // before initializing logging. This feels a little strange for
140 // a plugin. 96 // a plugin.
141 CommandLine::Init(0, NULL); 97 CommandLine::Init(0, NULL);
142 98
143 logging::InitLogging( 99 logging::InitLogging(
(...skipping 11 matching lines...) Expand all
155 111
156 // Needs to be called before we can use GURL. 112 // Needs to be called before we can use GURL.
157 chrome::RegisterChromeSchemes(); 113 chrome::RegisterChromeSchemes();
158 114
159 ScriptHost::set_default_debug_application(&debug_application); 115 ScriptHost::set_default_debug_application(&debug_application);
160 } 116 }
161 117
162 ToolbandModule::~ToolbandModule() { 118 ToolbandModule::~ToolbandModule() {
163 ScriptHost::set_default_debug_application(NULL); 119 ScriptHost::set_default_debug_application(NULL);
164 120
165 // Just leave thread as is. Releasing interface from this thread may hang IE. 121 DCHECK(!broker_rpc_client_.is_connected());
166 DCHECK(worker_thread_ref_count_ == 0);
167 DCHECK(worker_thread_ == NULL);
168 122
169 // Uninitialize control hosting. 123 // Uninitialize control hosting.
170 BOOL uninitialized = AtlAxWinTerm(); 124 BOOL uninitialized = AtlAxWinTerm();
171 DCHECK(uninitialized); 125 DCHECK(uninitialized);
172 126
173 logging::CloseLogFile(); 127 logging::CloseLogFile();
174 } 128 }
175 129
176 HRESULT ToolbandModule::DllCanUnloadNow() { 130 HRESULT ToolbandModule::DllCanUnloadNow() {
177 HRESULT hr = CAtlDllModuleT<ToolbandModule>::DllCanUnloadNow(); 131 HRESULT hr = CAtlDllModuleT<ToolbandModule>::DllCanUnloadNow();
178 if (hr == S_OK) { 132 if (hr == S_OK)
179 // We must protect our data member against concurrent calls to check if we 133 Term();
180 // can be unloaded. We must also making the call to Term within the lock
181 // to make sure we don't try to re-initialize in case a new
182 // DllGetClassObject would occur in the mean time, in another thread.
183 m_csStaticDataInitAndTypeInfo.Lock();
184 if (module_initialized_) {
185 Term();
186 }
187 m_csStaticDataInitAndTypeInfo.Unlock();
188 }
189 return hr; 134 return hr;
190 } 135 }
191 136
192 HRESULT ToolbandModule::DllGetClassObject(REFCLSID clsid, REFIID iid, 137 HRESULT ToolbandModule::DllGetClassObject(REFCLSID clsid, REFIID iid,
193 void** object) { 138 void** object) {
194 // Same comment as above in ToolbandModule::DllCanUnloadNow(). 139 Init();
195 m_csStaticDataInitAndTypeInfo.Lock();
196 if (!module_initialized_) {
197 Init();
198 }
199 m_csStaticDataInitAndTypeInfo.Unlock();
200 return CAtlDllModuleT<ToolbandModule>::DllGetClassObject(clsid, iid, object); 140 return CAtlDllModuleT<ToolbandModule>::DllGetClassObject(clsid, iid, object);
201 } 141 }
202 142
203 void ToolbandModule::Init() { 143 void ToolbandModule::Init() {
144 // We must protect our data member against concurrent calls to check if we
145 // can be unloaded. We must also making the call to Term within the lock
146 // to make sure we don't try to re-initialize in case a new
147 // DllGetClassObject would occur in the mean time, in another thread.
148 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo);
149 if (module_initialized_)
150 return;
204 crash_reporting_initialized_ = InitializeCrashReporting(); 151 crash_reporting_initialized_ = InitializeCrashReporting();
205 module_initialized_ = true; 152 module_initialized_ = true;
206 } 153 }
207 154
208 void ToolbandModule::Term() { 155 void ToolbandModule::Term() {
209 if (worker_thread_ != NULL) { 156 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo);
210 // It is OK to call Stop on a thread even when it isn't running. 157 if (!module_initialized_)
211 worker_thread_->Stop(); 158 return;
212 delete worker_thread_; 159 if (broker_rpc_client_.is_connected())
213 worker_thread_ = NULL; 160 broker_rpc_client_.Disconnect();
214 } 161
215 if (crash_reporting_initialized_) { 162 if (crash_reporting_initialized_) {
216 bool crash_reporting_deinitialized = ShutdownCrashReporting(); 163 bool crash_reporting_deinitialized = ShutdownCrashReporting();
217 DCHECK(crash_reporting_deinitialized); 164 DCHECK(crash_reporting_deinitialized);
218 crash_reporting_initialized_ = false; 165 crash_reporting_initialized_ = false;
219 } 166 }
220 module_initialized_ = false; 167 module_initialized_ = false;
221 } 168 }
222 169
223 void ToolbandModule::IncThreadRefCount() { 170 void ToolbandModule::IncBrokerRefCount() {
224 m_csStaticDataInitAndTypeInfo.Lock(); 171 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo);
225 DCHECK_GE(worker_thread_ref_count_, 0); 172 DCHECK_GE(broker_ref_count_, 0);
226 worker_thread_ref_count_++; 173 broker_ref_count_++;
227 m_csStaticDataInitAndTypeInfo.Unlock();
228 } 174 }
229 175
230 void ToolbandModule::DecThreadRefCount() { 176 void ToolbandModule::DecBrokerRefCount() {
231 ComWorkerThread* thread = NULL; 177 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo);
178 // If we're already at 0, we have a problem, so we check if we're >=.
179 DCHECK_GT(broker_ref_count_, 0);
232 180
233 m_csStaticDataInitAndTypeInfo.Lock(); 181 // If this was our last reference, we disconnect broker. This is okay even if
234 // If we're already at 0, we have a problem, so we check if we're >=. 182 // we increment the count again, because the broker is created on the "first"
235 DCHECK_GT(worker_thread_ref_count_, 0);
236
237 // If this was our last reference, we delete the thread. This is okay even if
238 // we increment the count again, because the thread is created on the "first"
239 // FireEventToBroker, thus it will be created again if needed. 183 // FireEventToBroker, thus it will be created again if needed.
240 if (--worker_thread_ref_count_ == 0) { 184 if (--broker_ref_count_ == 0) {
241 if (worker_thread_ != NULL) { 185 if (broker_rpc_client_.is_connected())
242 // Store the worker_thread to a temporary pointer. It will be freed later. 186 broker_rpc_client_.Disconnect();
243 thread = worker_thread_;
244 worker_thread_ = NULL;
245 }
246 }
247 m_csStaticDataInitAndTypeInfo.Unlock();
248
249 // Clean the thread after the unlock to be certain we don't get a deadlock
250 // (the CriticalSection could be used in the worker thread).
251 if (thread) {
252 // It is OK to call Stop on a thread even when it isn't running.
253 thread->Stop();
254 delete thread;
255 } 187 }
256 } 188 }
257 189
258 void ToolbandModule::EnsureThreadStarted() { 190 void ToolbandModule::EnsureBrokerIsConnected() {
259 m_csStaticDataInitAndTypeInfo.Lock(); 191 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo);
260 if (worker_thread_ == NULL) { 192 if (!broker_rpc_client_.is_connected()) {
261 worker_thread_ = new ComWorkerThread; 193 ::CoInitializeEx(0, COINIT_MULTITHREADED);
Sigurður Ásgeirsson 2010/11/16 18:23:04 I think we can skip the Coinit calls. We're runnin
Vitaly Buka corp 2010/11/18 23:14:21 Done.
262 // The COM worker thread must be a UI thread so that it can pump windows 194 // TODO(vitalybuka@google.com): Start broker without COM after the last
263 // messages and allow COM to handle cross apartment calls. 195 // COM interface is removed.
264 worker_thread_->StartWithOptions(base::Thread::Options(MessageLoop::TYPE_UI, 196 CComPtr<ICeeeBrokerRegistrar> broker;
265 0)); // stack_size 197 HRESULT hr = broker.CoCreateInstance(CLSID_CeeeBroker);
198 DCHECK(SUCCEEDED(hr)) << "Failed to create broker. " << com::LogHr(hr);
199 broker_rpc_client_.Connect();
Sigurður Ásgeirsson 2010/11/16 18:23:04 test return value and LOG(ERROR) here?
Vitaly Buka corp 2010/11/18 23:14:21 Done.
200 DCHECK(broker_rpc_client_.is_connected());
201 ::CoUninitialize();
Sigurður Ásgeirsson 2010/11/16 18:23:04 Ooof. If the ::Coinitialize call fails (e.g. due t
Vitaly Buka corp 2010/11/18 23:14:21 Done.
266 } 202 }
267 m_csStaticDataInitAndTypeInfo.Unlock();
268 } 203 }
269 204
270 void ToolbandModule::FireEventToBroker(const std::string& event_name, 205 void ToolbandModule::FireEventToBroker(const std::string& event_name,
271 const std::string& event_args) { 206 const std::string& event_args) {
272 EnsureThreadStarted(); 207 EnsureBrokerIsConnected();
273 DCHECK(worker_thread_ != NULL); 208 CComBSTR name(event_name.c_str());
Sigurður Ásgeirsson 2010/11/16 18:23:04 This looks like needless conversion and allocation
Vitaly Buka corp 2010/11/18 23:14:21 Done.
274 MessageLoop* message_loop = worker_thread_->message_loop(); 209 CComBSTR args(event_args.c_str());
275 if (message_loop) { 210 LOG_IF(ERROR, broker_rpc_client_.FireEvent(name, args)) <<
Sigurður Ásgeirsson 2010/11/16 18:23:04 Fire event returns true on error? I don't like hid
Vitaly Buka corp 2010/11/18 23:14:21 Done.
276 message_loop->PostTask(FROM_HERE, 211 "Failed to fire event to broker.";
277 new FireEventTask(worker_thread_, event_name, event_args));
278 } else {
279 LOG(ERROR) << "Trying to post a message before the COM worker thread is"
280 "completely initialized and ready.";
281 }
282 } 212 }
283 213
284 214
285 ToolbandModule::ComWorkerThread::ComWorkerThread()
286 : base::Thread("CEEE-COM Worker Thread") {
287 }
288
289 void ToolbandModule::ComWorkerThread::Init() {
290 ::CoInitializeEx(0, COINIT_MULTITHREADED);
291 // TODO(vitalybuka@google.com): Start broker without COM.
292 CComPtr<ICeeeBroker> broker_;
293 HRESULT hr = broker_.CoCreateInstance(CLSID_CeeeBroker);
294 DCHECK(SUCCEEDED(hr)) << "Failed to create broker. " << com::LogHr(hr);
295 broker_rpc_.Connect();
296 DCHECK(broker_rpc_.is_connected());
297 ::CoUninitialize();
298 }
299
300 void ToolbandModule::ComWorkerThread::CleanUp() {
301 broker_rpc_.Disconnect();
302 }
303
304 void ToolbandModule::ComWorkerThread::FireEventToBroker(BSTR event_name,
305 BSTR event_args) {
306 DCHECK(broker_rpc_.is_connected());
307 bool result = broker_rpc_.FireEvent(event_name, event_args);
308 DCHECK(result);
309 }
310
311 ToolbandModule module; 215 ToolbandModule module;
312 216
313 void ceee_module_util::AddRefModuleWorkerThread() { 217 void ceee_module_util::AddRefBroker() {
314 module.IncThreadRefCount(); 218 module.IncBrokerRefCount();
315 } 219 }
316 void ceee_module_util::ReleaseModuleWorkerThread() { 220 void ceee_module_util::ReleaseBroker() {
317 module.DecThreadRefCount(); 221 module.DecBrokerRefCount();
318 } 222 }
319 223
320 void ceee_module_util::FireEventToBroker(const std::string& event_name, 224 void ceee_module_util::FireEventToBroker(const std::string& event_name,
321 const std::string& event_args) { 225 const std::string& event_args) {
322 module.FireEventToBroker(event_name, event_args); 226 module.FireEventToBroker(event_name, event_args);
323 } 227 }
324 228
325 void ceee_module_util::Lock() { 229 void ceee_module_util::Lock() {
326 module.m_csStaticDataInitAndTypeInfo.Lock(); 230 module.m_csStaticDataInitAndTypeInfo.Lock();
327 } 231 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 } 282 }
379 283
380 CEEE_DEFINE_DLL_REGISTER_SERVER() 284 CEEE_DEFINE_DLL_REGISTER_SERVER()
381 285
382 // DllUnregisterServer - Removes entries from the system registry 286 // DllUnregisterServer - Removes entries from the system registry
383 STDAPI DllUnregisterServer(void) { 287 STDAPI DllUnregisterServer(void) {
384 // We always allow unregistration, even if no --enable-ceee install flag. 288 // We always allow unregistration, even if no --enable-ceee install flag.
385 HRESULT hr = module.DllUnregisterServer(); 289 HRESULT hr = module.DllUnregisterServer();
386 return hr; 290 return hr;
387 } 291 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698