/************************************************************** * * 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. * *************************************************************/ #include "precompiled_sw.hxx" #include #include #include using namespace ::com::sun::star; /** class to manage threads OD 2007-01-29 #i73788# @author OD */ const std::deque< ThreadManager::tThreadData >::size_type ThreadManager::mnStartedSize = 10; ThreadManager::ThreadManager( uno::Reference< util::XJobManager >& rThreadJoiner ) : maMutex(), mrThreadJoiner( rThreadJoiner ), mpThreadListener(), mnThreadIDCounter( 0 ), maWaitingForStartThreads(), maStartedThreads(), maStartNewThreadTimer(), mbStartingOfThreadsSuspended( false ) { } void ThreadManager::Init() { mpThreadListener.reset( new ThreadListener( *this ) ); maStartNewThreadTimer.SetTimeout( 2000 ); maStartNewThreadTimer.SetTimeoutHdl( LINK( this, ThreadManager, TryToStartNewThread ) ); } ThreadManager::~ThreadManager() { maWaitingForStartThreads.clear(); maStartedThreads.clear(); } boost::weak_ptr< IFinishedThreadListener > ThreadManager::GetThreadListenerWeakRef() { return mpThreadListener; } void ThreadManager::NotifyAboutFinishedThread( const oslInterlockedCount nThreadID ) { RemoveThread( nThreadID, true ); } oslInterlockedCount ThreadManager::AddThread( const rtl::Reference< ObservableThread >& rThread ) { osl::MutexGuard aGuard(maMutex); // create new thread tThreadData aThreadData; oslInterlockedCount nNewThreadID( RetrieveNewThreadID() ); { aThreadData.nThreadID = nNewThreadID; aThreadData.pThread = rThread; aThreadData.aJob = new CancellableJob( aThreadData.pThread ); aThreadData.pThread->setPriority( osl_Thread_PriorityBelowNormal ); mpThreadListener->ListenToThread( aThreadData.nThreadID, *(aThreadData.pThread) ); } // add thread to manager if ( maStartedThreads.size() < mnStartedSize && !StartingOfThreadsSuspended() ) { // Try to start thread if ( !StartThread( aThreadData ) ) { // No success on starting thread // If no more started threads exist, but still threads are waiting, // setup Timer to start thread from waiting ones if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) { maStartNewThreadTimer.Start(); } } } else { // Thread will be started later maWaitingForStartThreads.push_back( aThreadData ); } return nNewThreadID; } void ThreadManager::RemoveThread( const oslInterlockedCount nThreadID, const bool bThreadFinished ) { // --> SAFE ---- osl::MutexGuard aGuard(maMutex); std::deque< tThreadData >::iterator aIter = std::find_if( maStartedThreads.begin(), maStartedThreads.end(), ThreadPred( nThreadID ) ); if ( aIter != maStartedThreads.end() ) { tThreadData aTmpThreadData( (*aIter) ); maStartedThreads.erase( aIter ); if ( bThreadFinished ) { // release thread as job from thread joiner instance ::com::sun::star::uno::Reference< ::com::sun::star::util::XJobManager > rThreadJoiner( mrThreadJoiner ); if ( rThreadJoiner.is() ) { rThreadJoiner->releaseJob( aTmpThreadData.aJob ); } else { ASSERT( false, " - ThreadJoiner already gone!" ); } } // Try to start thread from waiting ones TryToStartNewThread( 0 ); } else { aIter = std::find_if( maWaitingForStartThreads.begin(), maWaitingForStartThreads.end(), ThreadPred( nThreadID ) ); if ( aIter != maWaitingForStartThreads.end() ) { maWaitingForStartThreads.erase( aIter ); } } // <-- SAFE ---- } bool ThreadManager::StartWaitingThread() { if ( !maWaitingForStartThreads.empty() ) { tThreadData aThreadData( maWaitingForStartThreads.front() ); maWaitingForStartThreads.pop_front(); return StartThread( aThreadData ); } else { return false; } } bool ThreadManager::StartThread( const tThreadData& rThreadData ) { bool bThreadStarted( false ); if ( rThreadData.pThread->create() ) { // start of thread successful. bThreadStarted = true; maStartedThreads.push_back( rThreadData ); // register thread as job at thread joiner instance ::com::sun::star::uno::Reference< ::com::sun::star::util::XJobManager > rThreadJoiner( mrThreadJoiner ); if ( rThreadJoiner.is() ) { rThreadJoiner->registerJob( rThreadData.aJob ); } else { ASSERT( false, " - ThreadJoiner already gone!" ); } } else { // thread couldn't be started. maWaitingForStartThreads.push_front( rThreadData ); } return bThreadStarted; } IMPL_LINK( ThreadManager, TryToStartNewThread, Timer *, EMPTYARG ) { osl::MutexGuard aGuard(maMutex); if ( !StartingOfThreadsSuspended() ) { // Try to start thread from waiting ones if ( !StartWaitingThread() ) { // No success on starting thread // If no more started threads exist, but still threads are waiting, // setup Timer to start thread from waiting ones if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) { maStartNewThreadTimer.Start(); } } } return sal_True; } void ThreadManager::ResumeStartingOfThreads() { osl::MutexGuard aGuard(maMutex); mbStartingOfThreadsSuspended = false; while ( maStartedThreads.size() < mnStartedSize && !maWaitingForStartThreads.empty() ) { if ( !StartWaitingThread() ) { // No success on starting thread // If no more started threads exist, but still threads are waiting, // setup Timer to start thread from waiting ones if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) { maStartNewThreadTimer.Start(); break; } } } }