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