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

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
« no previous file with comments | « ceee/ie/plugin/bho/webrequest_events_funnel.h ('k') | ceee/ie/testing/ie_unittest_main.cc » ('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) 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"
16 #include "ceee/ie/common/ceee_module_util.h" 14 #include "ceee/ie/common/ceee_module_util.h"
17 #include "ceee/ie/plugin/bho/browser_helper_object.h" 15 #include "ceee/ie/plugin/bho/browser_helper_object.h"
18 #include "ceee/ie/plugin/bho/executor.h" 16 #include "ceee/ie/plugin/bho/executor.h"
19 #include "ceee/ie/plugin/toolband/toolband_module_reporting.h" 17 #include "ceee/ie/plugin/toolband/toolband_module_reporting.h"
20 #include "ceee/ie/plugin/toolband/tool_band.h" 18 #include "ceee/ie/plugin/toolband/tool_band.h"
21 #include "ceee/ie/plugin/scripting/script_host.h" 19 #include "ceee/ie/plugin/scripting/script_host.h"
22 #include "ceee/common/windows_constants.h" 20 #include "ceee/common/windows_constants.h"
23 #include "chrome/common/url_constants.h" 21 #include "chrome/common/url_constants.h"
24 22
25 #include "toolband.h" // NOLINT 23 #include "toolband.h" // NOLINT
(...skipping 28 matching lines...) Expand all
54 52
55 // Needed to make sure we call Init/Term outside the loader lock. 53 // Needed to make sure we call Init/Term outside the loader lock.
56 HRESULT DllCanUnloadNow(); 54 HRESULT DllCanUnloadNow();
57 HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** object); 55 HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** object);
58 void Init(); 56 void Init();
59 void Term(); 57 void Term();
60 bool module_initialized() const { 58 bool module_initialized() const {
61 return module_initialized_; 59 return module_initialized_;
62 } 60 }
63 61
64 // Fires an event to the broker, so that the call can be made with an 62 private:
65 // instance of a broker proxy that was CoCreated in the worker thread.
66 void FireEventToBroker(const std::string& event_name,
67 const std::string& event_args);
68 63
69 private:
70 // TODO(vitalybuka@google.com): Fire events without this thread.
71 class ComWorkerThread : public base::Thread {
72 public:
73 ComWorkerThread();
74
75 // Called just prior to starting the message loop
76 virtual void Init();
77
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_; 64 base::AtExitManager at_exit_;
118 bool module_initialized_; 65 bool module_initialized_;
119 bool crash_reporting_initialized_; 66 bool crash_reporting_initialized_;
120
121 int worker_thread_ref_count_;
122
123 friend void ceee_module_util::AddRefModuleWorkerThread();
124 friend void ceee_module_util::ReleaseModuleWorkerThread();
125
126 void IncThreadRefCount();
127 void DecThreadRefCount();
128 }; 67 };
129 68
130 ToolbandModule::ToolbandModule() 69 ToolbandModule::ToolbandModule()
131 : crash_reporting_initialized_(false), 70 : crash_reporting_initialized_(false),
132 module_initialized_(false), 71 module_initialized_(false) {
133 worker_thread_(NULL) {
134 wchar_t logfile_path[MAX_PATH]; 72 wchar_t logfile_path[MAX_PATH];
135 DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path); 73 DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path);
136 ::PathAppend(logfile_path, kLogFileName); 74 ::PathAppend(logfile_path, kLogFileName);
137 75
138 // It seems we're obliged to initialize the current command line 76 // It seems we're obliged to initialize the current command line
139 // before initializing logging. This feels a little strange for 77 // before initializing logging. This feels a little strange for
140 // a plugin. 78 // a plugin.
141 CommandLine::Init(0, NULL); 79 CommandLine::Init(0, NULL);
142 80
143 logging::InitLogging( 81 logging::InitLogging(
(...skipping 11 matching lines...) Expand all
155 93
156 // Needs to be called before we can use GURL. 94 // Needs to be called before we can use GURL.
157 chrome::RegisterChromeSchemes(); 95 chrome::RegisterChromeSchemes();
158 96
159 ScriptHost::set_default_debug_application(&debug_application); 97 ScriptHost::set_default_debug_application(&debug_application);
160 } 98 }
161 99
162 ToolbandModule::~ToolbandModule() { 100 ToolbandModule::~ToolbandModule() {
163 ScriptHost::set_default_debug_application(NULL); 101 ScriptHost::set_default_debug_application(NULL);
164 102
165 // Just leave thread as is. Releasing interface from this thread may hang IE.
166 DCHECK(worker_thread_ref_count_ == 0);
167 DCHECK(worker_thread_ == NULL);
168
169 // Uninitialize control hosting. 103 // Uninitialize control hosting.
170 BOOL uninitialized = AtlAxWinTerm(); 104 BOOL uninitialized = AtlAxWinTerm();
171 DCHECK(uninitialized); 105 DCHECK(uninitialized);
172 106
173 logging::CloseLogFile(); 107 logging::CloseLogFile();
174 } 108 }
175 109
176 HRESULT ToolbandModule::DllCanUnloadNow() { 110 HRESULT ToolbandModule::DllCanUnloadNow() {
177 HRESULT hr = CAtlDllModuleT<ToolbandModule>::DllCanUnloadNow(); 111 HRESULT hr = CAtlDllModuleT<ToolbandModule>::DllCanUnloadNow();
178 if (hr == S_OK) { 112 if (hr == S_OK)
179 // We must protect our data member against concurrent calls to check if we 113 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; 114 return hr;
190 } 115 }
191 116
192 HRESULT ToolbandModule::DllGetClassObject(REFCLSID clsid, REFIID iid, 117 HRESULT ToolbandModule::DllGetClassObject(REFCLSID clsid, REFIID iid,
193 void** object) { 118 void** object) {
194 // Same comment as above in ToolbandModule::DllCanUnloadNow(). 119 Init();
195 m_csStaticDataInitAndTypeInfo.Lock();
196 if (!module_initialized_) {
197 Init();
198 }
199 m_csStaticDataInitAndTypeInfo.Unlock();
200 return CAtlDllModuleT<ToolbandModule>::DllGetClassObject(clsid, iid, object); 120 return CAtlDllModuleT<ToolbandModule>::DllGetClassObject(clsid, iid, object);
201 } 121 }
202 122
203 void ToolbandModule::Init() { 123 void ToolbandModule::Init() {
124 // We must protect our data member against concurrent calls to check if we
125 // can be unloaded. We must also making the call to Term within the lock
126 // to make sure we don't try to re-initialize in case a new
127 // DllGetClassObject would occur in the mean time, in another thread.
128 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo);
129 if (module_initialized_)
130 return;
204 crash_reporting_initialized_ = InitializeCrashReporting(); 131 crash_reporting_initialized_ = InitializeCrashReporting();
205 module_initialized_ = true; 132 module_initialized_ = true;
206 } 133 }
207 134
208 void ToolbandModule::Term() { 135 void ToolbandModule::Term() {
209 if (worker_thread_ != NULL) { 136 CComCritSecLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo);
210 // It is OK to call Stop on a thread even when it isn't running. 137 if (!module_initialized_)
211 worker_thread_->Stop(); 138 return;
212 delete worker_thread_;
213 worker_thread_ = NULL;
214 }
215 if (crash_reporting_initialized_) { 139 if (crash_reporting_initialized_) {
216 bool crash_reporting_deinitialized = ShutdownCrashReporting(); 140 bool crash_reporting_deinitialized = ShutdownCrashReporting();
217 DCHECK(crash_reporting_deinitialized); 141 DCHECK(crash_reporting_deinitialized);
218 crash_reporting_initialized_ = false; 142 crash_reporting_initialized_ = false;
219 } 143 }
220 module_initialized_ = false; 144 module_initialized_ = false;
221 } 145 }
222 146
223 void ToolbandModule::IncThreadRefCount() {
224 m_csStaticDataInitAndTypeInfo.Lock();
225 DCHECK_GE(worker_thread_ref_count_, 0);
226 worker_thread_ref_count_++;
227 m_csStaticDataInitAndTypeInfo.Unlock();
228 }
229
230 void ToolbandModule::DecThreadRefCount() {
231 ComWorkerThread* thread = NULL;
232
233 m_csStaticDataInitAndTypeInfo.Lock();
234 // If we're already at 0, we have a problem, so we check if we're >=.
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.
240 if (--worker_thread_ref_count_ == 0) {
241 if (worker_thread_ != NULL) {
242 // Store the worker_thread to a temporary pointer. It will be freed later.
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 }
256 }
257
258 void ToolbandModule::EnsureThreadStarted() {
259 m_csStaticDataInitAndTypeInfo.Lock();
260 if (worker_thread_ == NULL) {
261 worker_thread_ = new ComWorkerThread;
262 // The COM worker thread must be a UI thread so that it can pump windows
263 // messages and allow COM to handle cross apartment calls.
264 worker_thread_->StartWithOptions(base::Thread::Options(MessageLoop::TYPE_UI,
265 0)); // stack_size
266 }
267 m_csStaticDataInitAndTypeInfo.Unlock();
268 }
269
270 void ToolbandModule::FireEventToBroker(const std::string& event_name,
271 const std::string& event_args) {
272 EnsureThreadStarted();
273 DCHECK(worker_thread_ != NULL);
274 MessageLoop* message_loop = worker_thread_->message_loop();
275 if (message_loop) {
276 message_loop->PostTask(FROM_HERE,
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 }
283
284
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; 147 ToolbandModule module;
312 148
313 void ceee_module_util::AddRefModuleWorkerThread() {
314 module.IncThreadRefCount();
315 }
316 void ceee_module_util::ReleaseModuleWorkerThread() {
317 module.DecThreadRefCount();
318 }
319
320 void ceee_module_util::FireEventToBroker(const std::string& event_name,
321 const std::string& event_args) {
322 module.FireEventToBroker(event_name, event_args);
323 }
324
325 void ceee_module_util::Lock() { 149 void ceee_module_util::Lock() {
326 module.m_csStaticDataInitAndTypeInfo.Lock(); 150 module.m_csStaticDataInitAndTypeInfo.Lock();
327 } 151 }
328 152
329 void ceee_module_util::Unlock() { 153 void ceee_module_util::Unlock() {
330 module.m_csStaticDataInitAndTypeInfo.Unlock(); 154 module.m_csStaticDataInitAndTypeInfo.Unlock();
331 } 155 }
332 156
333 LONG ceee_module_util::LockModule() { 157 LONG ceee_module_util::LockModule() {
334 return module.Lock(); 158 return module.Lock();
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 } 202 }
379 203
380 CEEE_DEFINE_DLL_REGISTER_SERVER() 204 CEEE_DEFINE_DLL_REGISTER_SERVER()
381 205
382 // DllUnregisterServer - Removes entries from the system registry 206 // DllUnregisterServer - Removes entries from the system registry
383 STDAPI DllUnregisterServer(void) { 207 STDAPI DllUnregisterServer(void) {
384 // We always allow unregistration, even if no --enable-ceee install flag. 208 // We always allow unregistration, even if no --enable-ceee install flag.
385 HRESULT hr = module.DllUnregisterServer(); 209 HRESULT hr = module.DllUnregisterServer();
386 return hr; 210 return hr;
387 } 211 }
OLDNEW
« no previous file with comments | « ceee/ie/plugin/bho/webrequest_events_funnel.h ('k') | ceee/ie/testing/ie_unittest_main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698