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