/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_fpicker.hxx" //------------------------------------------------------------------------ // includes //------------------------------------------------------------------------ #include #include "asynceventnotifier.hxx" #include #include #include #include #include "SolarMutex.hxx" //------------------------------------------------ // //------------------------------------------------ using namespace com::sun::star; using ::com::sun::star::ui::dialogs::XFilePickerListener; //------------------------------------------------ // //------------------------------------------------ CAsyncEventNotifier::CAsyncEventNotifier(cppu::OBroadcastHelper& rBroadcastHelper) : m_hThread(0), m_bRun(false), m_ThreadId(0), m_rBroadcastHelper(rBroadcastHelper), m_NotifyEvent(m_hEvents[0]), m_ResumeNotifying(m_hEvents[1]) { // m_NotifyEvent m_hEvents[0] = CreateEvent(0, /* no security */ true, /* manual reset */ false, /* initial state not signaled */ 0); /* automatic name */ // m_ResumeNotifying m_hEvents[1] = CreateEvent(0, /* no security */ true, /* manual reset */ false, /* initial state not signaled */ 0); /* automatic name */ } //------------------------------------------------ // //------------------------------------------------ CAsyncEventNotifier::~CAsyncEventNotifier() { OSL_ENSURE(0 == m_hThread,"Thread not stopped, destroying this instance leads to desaster"); CloseHandle(m_hEvents[0]); CloseHandle(m_hEvents[1]); } //------------------------------------------------ // //------------------------------------------------ void SAL_CALL CAsyncEventNotifier::addListener(const uno::Type& aType , const uno::Reference< uno::XInterface >& xListener) { if ( m_rBroadcastHelper.bDisposed ) throw lang::DisposedException( ::rtl::OUString::createFromAscii( "FilePicker is already disposed" ), uno::Reference< uno::XInterface >() ); if ( m_rBroadcastHelper.bInDispose ) throw lang::DisposedException( ::rtl::OUString::createFromAscii( "FilePicker will be disposed now." ), uno::Reference< uno::XInterface >() ); m_rBroadcastHelper.aLC.addInterface( aType, xListener ); } //------------------------------------------------ // //------------------------------------------------ void SAL_CALL CAsyncEventNotifier::removeListener(const uno::Type& aType , const uno::Reference< uno::XInterface >& xListener) { if ( m_rBroadcastHelper.bDisposed ) throw lang::DisposedException( ::rtl::OUString::createFromAscii( "FilePicker is already disposed." ), uno::Reference< uno::XInterface >() ); m_rBroadcastHelper.aLC.removeInterface( aType, xListener ); } //------------------------------------------------ // //------------------------------------------------ bool SAL_CALL CAsyncEventNotifier::startup(bool bCreateSuspended) { osl::MutexGuard aGuard(m_Mutex); // m_bRun may already be false because of a // call to stop but the thread did not yet // terminate so m_hEventNotifierThread is // yet a valid thread handle that should // not be overwritten if (!m_bRun) { if (!bCreateSuspended) SetEvent(m_ResumeNotifying); m_hThread = (HANDLE)_beginthreadex( NULL, 0, CAsyncEventNotifier::ThreadProc, this, 0, &m_ThreadId); OSL_ASSERT(0 != m_hThread); if (m_hThread) m_bRun = true; } OSL_POSTCOND(m_bRun,"Could not start event notifier!"); return m_bRun; } //------------------------------------------------ // //------------------------------------------------ void SAL_CALL CAsyncEventNotifier::shutdown() { unsigned nThreadId = GetCurrentThreadId(); OSL_PRECOND(nThreadId != m_ThreadId, "Method called in wrong thread context!"); osl::ResettableMutexGuard aGuard(m_Mutex); OSL_PRECOND(m_bRun,"Event notifier does not run!"); m_bRun = false; m_EventList.clear(); // awake the notifier thread SetEvent(m_ResumeNotifying); SetEvent(m_NotifyEvent); // releas the mutex here because the event // notifier thread may need it to finish aGuard.clear(); // we are waiting infinite, so error will // be better detected in form of deadlocks if (WaitForSingleObject(m_hThread, INFINITE) == WAIT_FAILED) { OSL_ENSURE(false, "Waiting for thread termination failed!"); } // lock mutex again to reset m_hThread // and prevent a race with start() aGuard.reset(); CloseHandle(m_hThread); m_hThread = 0; } //------------------------------------------------ // //------------------------------------------------ void CAsyncEventNotifier::suspend() { ResetEvent(m_ResumeNotifying); } //------------------------------------------------ // //------------------------------------------------ void CAsyncEventNotifier::resume() { SetEvent(m_ResumeNotifying); } //------------------------------------------------ // //------------------------------------------------ void SAL_CALL CAsyncEventNotifier::notifyEvent(CEventNotification* EventNotification) { osl::MutexGuard aGuard(m_Mutex); OSL_ENSURE(m_bRun,"Event notifier is not running!"); if (m_bRun) { m_EventList.push_back(EventNotification); SetEvent(m_NotifyEvent); } } //------------------------------------------------ // //------------------------------------------------ size_t SAL_CALL CAsyncEventNotifier::getEventListSize() { osl::MutexGuard aGuard(m_Mutex); return m_EventList.size(); } //------------------------------------------------ // //------------------------------------------------ void SAL_CALL CAsyncEventNotifier::resetNotifyEvent() { osl::MutexGuard aGuard(m_Mutex); if (0 == m_EventList.size()) ResetEvent(m_NotifyEvent); } //------------------------------------------------ // //------------------------------------------------ CEventNotification* SAL_CALL CAsyncEventNotifier::getNextEventRecord() { osl::MutexGuard aGuard(m_Mutex); return m_EventList.front(); } //------------------------------------------------ // //------------------------------------------------ void SAL_CALL CAsyncEventNotifier::removeNextEventRecord() { osl::MutexGuard aGuard(m_Mutex); m_EventList.pop_front(); } //------------------------------------------------ // //------------------------------------------------ void SAL_CALL CAsyncEventNotifier::run() { while (m_bRun) { WaitForMultipleObjects(2, m_hEvents, true, INFINITE); if (m_bRun) { while (getEventListSize() > 0) { std::auto_ptr EventNotification(getNextEventRecord()); removeNextEventRecord(); ::cppu::OInterfaceContainerHelper* pICHelper = m_rBroadcastHelper.getContainer(getCppuType((uno::Reference*)0)); if (pICHelper) { ::cppu::OInterfaceIteratorHelper iter(*pICHelper); while(iter.hasMoreElements()) { try { EventNotification->notifyEventListener(iter.next()); } catch(uno::RuntimeException&) { OSL_ENSURE(sal_False,"RuntimeException during event dispatching"); } } } } // while(getEventListSize() > 0) resetNotifyEvent(); } // if (m_bRun) } // while(m_bRun) } //------------------------------------------------ // //------------------------------------------------ unsigned int WINAPI CAsyncEventNotifier::ThreadProc(LPVOID pParam) { CAsyncEventNotifier* pInst = reinterpret_cast< CAsyncEventNotifier* >(pParam); OSL_ASSERT(pInst); pInst->run(); return 0; }