1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_fpicker.hxx" 26 27 //------------------------------------------------------------------------ 28 // includes 29 //------------------------------------------------------------------------ 30 #include <osl/diagnose.h> 31 #include "asynceventnotifier.hxx" 32 #include <com/sun/star/uno/RuntimeException.hpp> 33 #include <com/sun/star/ui/dialogs/XFilePickerListener.hpp> 34 35 #include <process.h> 36 #include <memory> 37 #include "SolarMutex.hxx" 38 39 //------------------------------------------------ 40 // 41 //------------------------------------------------ 42 43 using namespace com::sun::star; 44 using ::com::sun::star::ui::dialogs::XFilePickerListener; 45 46 //------------------------------------------------ 47 // 48 //------------------------------------------------ 49 50 CAsyncEventNotifier::CAsyncEventNotifier(cppu::OBroadcastHelper& rBroadcastHelper) : 51 m_hThread(0), 52 m_bRun(false), 53 m_ThreadId(0), 54 m_rBroadcastHelper(rBroadcastHelper), 55 m_NotifyEvent(m_hEvents[0]), 56 m_ResumeNotifying(m_hEvents[1]) 57 { 58 // m_NotifyEvent 59 m_hEvents[0] = CreateEvent(0, /* no security */ 60 true, /* manual reset */ 61 false, /* initial state not signaled */ 62 0); /* automatic name */ 63 64 // m_ResumeNotifying 65 m_hEvents[1] = CreateEvent(0, /* no security */ 66 true, /* manual reset */ 67 false, /* initial state not signaled */ 68 0); /* automatic name */ 69 } 70 71 //------------------------------------------------ 72 // 73 //------------------------------------------------ 74 75 CAsyncEventNotifier::~CAsyncEventNotifier() 76 { 77 OSL_ENSURE(0 == m_hThread,"Thread not stopped, destroying this instance leads to desaster"); 78 79 CloseHandle(m_hEvents[0]); 80 CloseHandle(m_hEvents[1]); 81 } 82 83 //------------------------------------------------ 84 // 85 //------------------------------------------------ 86 87 void SAL_CALL CAsyncEventNotifier::addListener(const uno::Type& aType , 88 const uno::Reference< uno::XInterface >& xListener) 89 { 90 if ( m_rBroadcastHelper.bDisposed ) 91 throw lang::DisposedException( 92 ::rtl::OUString::createFromAscii( "FilePicker is already disposed" ), 93 uno::Reference< uno::XInterface >() ); 94 95 if ( m_rBroadcastHelper.bInDispose ) 96 throw lang::DisposedException( 97 ::rtl::OUString::createFromAscii( "FilePicker will be disposed now." ), 98 uno::Reference< uno::XInterface >() ); 99 100 m_rBroadcastHelper.aLC.addInterface( aType, xListener ); 101 } 102 103 //------------------------------------------------ 104 // 105 //------------------------------------------------ 106 107 void SAL_CALL CAsyncEventNotifier::removeListener(const uno::Type& aType , 108 const uno::Reference< uno::XInterface >& xListener) 109 { 110 if ( m_rBroadcastHelper.bDisposed ) 111 throw lang::DisposedException( 112 ::rtl::OUString::createFromAscii( "FilePicker is already disposed." ), 113 uno::Reference< uno::XInterface >() ); 114 115 m_rBroadcastHelper.aLC.removeInterface( aType, xListener ); 116 } 117 118 //------------------------------------------------ 119 // 120 //------------------------------------------------ 121 122 bool SAL_CALL CAsyncEventNotifier::startup(bool bCreateSuspended) 123 { 124 osl::MutexGuard aGuard(m_Mutex); 125 126 // m_bRun may already be false because of a 127 // call to stop but the thread did not yet 128 // terminate so m_hEventNotifierThread is 129 // yet a valid thread handle that should 130 // not be overwritten 131 if (!m_bRun) 132 { 133 if (!bCreateSuspended) 134 SetEvent(m_ResumeNotifying); 135 136 m_hThread = (HANDLE)_beginthreadex( 137 NULL, 0, CAsyncEventNotifier::ThreadProc, this, 0, &m_ThreadId); 138 139 OSL_ASSERT(0 != m_hThread); 140 141 if (m_hThread) 142 m_bRun = true; 143 } 144 145 OSL_POSTCOND(m_bRun,"Could not start event notifier!"); 146 147 return m_bRun; 148 } 149 150 //------------------------------------------------ 151 // 152 //------------------------------------------------ 153 154 void SAL_CALL CAsyncEventNotifier::shutdown() 155 { 156 unsigned nThreadId = GetCurrentThreadId(); 157 158 OSL_PRECOND(nThreadId != m_ThreadId, "Method called in wrong thread context!"); 159 160 osl::ResettableMutexGuard aGuard(m_Mutex); 161 162 OSL_PRECOND(m_bRun,"Event notifier does not run!"); 163 164 m_bRun = false; 165 m_EventList.clear(); 166 167 // awake the the notifier thread 168 SetEvent(m_ResumeNotifying); 169 SetEvent(m_NotifyEvent); 170 171 // releas the mutex here because the event 172 // notifier thread may need it to finish 173 aGuard.clear(); 174 175 // we are waiting infinite, so error will 176 // be better detected in form of deadlocks 177 if (WaitForSingleObject(m_hThread, INFINITE) == WAIT_FAILED) { 178 OSL_ENSURE(false, "Waiting for thread termination failed!"); 179 } 180 181 // lock mutex again to reset m_hThread 182 // and prevent a race with start() 183 aGuard.reset(); 184 185 CloseHandle(m_hThread); 186 m_hThread = 0; 187 } 188 189 //------------------------------------------------ 190 // 191 //------------------------------------------------ 192 193 void CAsyncEventNotifier::suspend() 194 { 195 ResetEvent(m_ResumeNotifying); 196 } 197 198 //------------------------------------------------ 199 // 200 //------------------------------------------------ 201 202 void CAsyncEventNotifier::resume() 203 { 204 SetEvent(m_ResumeNotifying); 205 } 206 207 //------------------------------------------------ 208 // 209 //------------------------------------------------ 210 211 void SAL_CALL CAsyncEventNotifier::notifyEvent(CEventNotification* EventNotification) 212 { 213 osl::MutexGuard aGuard(m_Mutex); 214 215 OSL_ENSURE(m_bRun,"Event notifier is not running!"); 216 217 if (m_bRun) 218 { 219 m_EventList.push_back(EventNotification); 220 SetEvent(m_NotifyEvent); 221 } 222 } 223 224 //------------------------------------------------ 225 // 226 //------------------------------------------------ 227 228 size_t SAL_CALL CAsyncEventNotifier::getEventListSize() 229 { 230 osl::MutexGuard aGuard(m_Mutex); 231 return m_EventList.size(); 232 } 233 234 //------------------------------------------------ 235 // 236 //------------------------------------------------ 237 238 void SAL_CALL CAsyncEventNotifier::resetNotifyEvent() 239 { 240 osl::MutexGuard aGuard(m_Mutex); 241 if (0 == m_EventList.size()) 242 ResetEvent(m_NotifyEvent); 243 } 244 245 //------------------------------------------------ 246 // 247 //------------------------------------------------ 248 249 CEventNotification* SAL_CALL CAsyncEventNotifier::getNextEventRecord() 250 { 251 osl::MutexGuard aGuard(m_Mutex); 252 return m_EventList.front(); 253 } 254 255 //------------------------------------------------ 256 // 257 //------------------------------------------------ 258 259 void SAL_CALL CAsyncEventNotifier::removeNextEventRecord() 260 { 261 osl::MutexGuard aGuard(m_Mutex); 262 m_EventList.pop_front(); 263 } 264 265 //------------------------------------------------ 266 // 267 //------------------------------------------------ 268 269 void SAL_CALL CAsyncEventNotifier::run() 270 { 271 while (m_bRun) 272 { 273 WaitForMultipleObjects(2, m_hEvents, true, INFINITE); 274 275 if (m_bRun) 276 { 277 while (getEventListSize() > 0) 278 { 279 std::auto_ptr<CEventNotification> EventNotification(getNextEventRecord()); 280 removeNextEventRecord(); 281 282 ::cppu::OInterfaceContainerHelper* pICHelper = 283 m_rBroadcastHelper.getContainer(getCppuType((uno::Reference<XFilePickerListener>*)0)); 284 285 if (pICHelper) 286 { 287 ::cppu::OInterfaceIteratorHelper iter(*pICHelper); 288 289 while(iter.hasMoreElements()) 290 { 291 try 292 { 293 EventNotification->notifyEventListener(iter.next()); 294 } 295 catch(uno::RuntimeException&) 296 { 297 OSL_ENSURE(sal_False,"RuntimeException during event dispatching"); 298 } 299 } 300 } 301 302 } // while(getEventListSize() > 0) 303 304 resetNotifyEvent(); 305 306 } // if (m_bRun) 307 308 } // while(m_bRun) 309 } 310 311 //------------------------------------------------ 312 // 313 //------------------------------------------------ 314 315 unsigned int WINAPI CAsyncEventNotifier::ThreadProc(LPVOID pParam) 316 { 317 CAsyncEventNotifier* pInst = reinterpret_cast< CAsyncEventNotifier* >(pParam); 318 OSL_ASSERT(pInst); 319 320 pInst->run(); 321 322 return 0; 323 } 324