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