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