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 #include "precompiled_sw.hxx" 24 #include <threadmanager.hxx> 25 #include <errhdl.hxx> 26 27 #include <algorithm> 28 29 using namespace ::com::sun::star; 30 31 /** class to manage threads 32 33 OD 2007-01-29 #i73788# 34 35 @author OD 36 */ 37 const std::deque< ThreadManager::tThreadData >::size_type ThreadManager::mnStartedSize = 10; 38 39 ThreadManager::ThreadManager( uno::Reference< util::XJobManager >& rThreadJoiner ) 40 : maMutex(), 41 mrThreadJoiner( rThreadJoiner ), 42 mpThreadListener(), 43 mnThreadIDCounter( 0 ), 44 maWaitingForStartThreads(), 45 maStartedThreads(), 46 maStartNewThreadTimer(), 47 mbStartingOfThreadsSuspended( false ) 48 { 49 } 50 51 void ThreadManager::Init() 52 { 53 mpThreadListener.reset( new ThreadListener( *this ) ); 54 55 maStartNewThreadTimer.SetTimeout( 2000 ); 56 maStartNewThreadTimer.SetTimeoutHdl( LINK( this, ThreadManager, TryToStartNewThread ) ); 57 } 58 59 ThreadManager::~ThreadManager() 60 { 61 maWaitingForStartThreads.clear(); 62 maStartedThreads.clear(); 63 } 64 65 boost::weak_ptr< IFinishedThreadListener > ThreadManager::GetThreadListenerWeakRef() 66 { 67 return mpThreadListener; 68 } 69 70 void ThreadManager::NotifyAboutFinishedThread( const oslInterlockedCount nThreadID ) 71 { 72 RemoveThread( nThreadID, true ); 73 } 74 75 oslInterlockedCount ThreadManager::AddThread( 76 const rtl::Reference< ObservableThread >& rThread ) 77 78 { 79 osl::MutexGuard aGuard(maMutex); 80 81 // create new thread 82 tThreadData aThreadData; 83 oslInterlockedCount nNewThreadID( RetrieveNewThreadID() ); 84 { 85 aThreadData.nThreadID = nNewThreadID; 86 87 aThreadData.pThread = rThread; 88 aThreadData.aJob = new CancellableJob( aThreadData.pThread ); 89 90 aThreadData.pThread->setPriority( osl_Thread_PriorityBelowNormal ); 91 mpThreadListener->ListenToThread( aThreadData.nThreadID, 92 *(aThreadData.pThread) ); 93 } 94 95 // add thread to manager 96 if ( maStartedThreads.size() < mnStartedSize && 97 !StartingOfThreadsSuspended() ) 98 { 99 // Try to start thread 100 if ( !StartThread( aThreadData ) ) 101 { 102 // No success on starting thread 103 // If no more started threads exist, but still threads are waiting, 104 // setup Timer to start thread from waiting ones 105 if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) 106 { 107 maStartNewThreadTimer.Start(); 108 } 109 } 110 } 111 else 112 { 113 // Thread will be started later 114 maWaitingForStartThreads.push_back( aThreadData ); 115 } 116 117 return nNewThreadID; 118 } 119 120 void ThreadManager::RemoveThread( const oslInterlockedCount nThreadID, 121 const bool bThreadFinished ) 122 { 123 // --> SAFE ---- 124 osl::MutexGuard aGuard(maMutex); 125 126 std::deque< tThreadData >::iterator aIter = 127 std::find_if( maStartedThreads.begin(), maStartedThreads.end(), 128 ThreadPred( nThreadID ) ); 129 130 if ( aIter != maStartedThreads.end() ) 131 { 132 tThreadData aTmpThreadData( (*aIter) ); 133 134 maStartedThreads.erase( aIter ); 135 136 if ( bThreadFinished ) 137 { 138 // release thread as job from thread joiner instance 139 ::com::sun::star::uno::Reference< ::com::sun::star::util::XJobManager > rThreadJoiner( mrThreadJoiner ); 140 if ( rThreadJoiner.is() ) 141 { 142 rThreadJoiner->releaseJob( aTmpThreadData.aJob ); 143 } 144 else 145 { 146 ASSERT( false, "<ThreadManager::RemoveThread(..)> - ThreadJoiner already gone!" ); 147 } 148 } 149 150 // Try to start thread from waiting ones 151 TryToStartNewThread( 0 ); 152 } 153 else 154 { 155 aIter = std::find_if( maWaitingForStartThreads.begin(), 156 maWaitingForStartThreads.end(), ThreadPred( nThreadID ) ); 157 158 if ( aIter != maWaitingForStartThreads.end() ) 159 { 160 maWaitingForStartThreads.erase( aIter ); 161 } 162 } 163 // <-- SAFE ---- 164 } 165 166 bool ThreadManager::StartWaitingThread() 167 { 168 if ( !maWaitingForStartThreads.empty() ) 169 { 170 tThreadData aThreadData( maWaitingForStartThreads.front() ); 171 maWaitingForStartThreads.pop_front(); 172 return StartThread( aThreadData ); 173 } 174 else 175 { 176 return false; 177 } 178 } 179 180 bool ThreadManager::StartThread( const tThreadData& rThreadData ) 181 { 182 bool bThreadStarted( false ); 183 184 if ( rThreadData.pThread->create() ) 185 { 186 // start of thread successful. 187 bThreadStarted = true; 188 189 maStartedThreads.push_back( rThreadData ); 190 191 // register thread as job at thread joiner instance 192 ::com::sun::star::uno::Reference< ::com::sun::star::util::XJobManager > rThreadJoiner( mrThreadJoiner ); 193 if ( rThreadJoiner.is() ) 194 { 195 rThreadJoiner->registerJob( rThreadData.aJob ); 196 } 197 else 198 { 199 ASSERT( false, "<ThreadManager::StartThread(..)> - ThreadJoiner already gone!" ); 200 } 201 } 202 else 203 { 204 // thread couldn't be started. 205 maWaitingForStartThreads.push_front( rThreadData ); 206 } 207 208 return bThreadStarted; 209 } 210 211 IMPL_LINK( ThreadManager, TryToStartNewThread, Timer *, EMPTYARG ) 212 { 213 osl::MutexGuard aGuard(maMutex); 214 215 if ( !StartingOfThreadsSuspended() ) 216 { 217 // Try to start thread from waiting ones 218 if ( !StartWaitingThread() ) 219 { 220 // No success on starting thread 221 // If no more started threads exist, but still threads are waiting, 222 // setup Timer to start thread from waiting ones 223 if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) 224 { 225 maStartNewThreadTimer.Start(); 226 } 227 } 228 } 229 230 return sal_True; 231 } 232 233 void ThreadManager::ResumeStartingOfThreads() 234 { 235 osl::MutexGuard aGuard(maMutex); 236 237 mbStartingOfThreadsSuspended = false; 238 239 while ( maStartedThreads.size() < mnStartedSize && 240 !maWaitingForStartThreads.empty() ) 241 { 242 if ( !StartWaitingThread() ) 243 { 244 // No success on starting thread 245 // If no more started threads exist, but still threads are waiting, 246 // setup Timer to start thread from waiting ones 247 if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) 248 { 249 maStartNewThreadTimer.Start(); 250 break; 251 } 252 } 253 } 254 } 255