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
ThreadManager(uno::Reference<util::XJobManager> & rThreadJoiner)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
Init()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
~ThreadManager()59 ThreadManager::~ThreadManager()
60 {
61 maWaitingForStartThreads.clear();
62 maStartedThreads.clear();
63 }
64
GetThreadListenerWeakRef()65 boost::weak_ptr< IFinishedThreadListener > ThreadManager::GetThreadListenerWeakRef()
66 {
67 return mpThreadListener;
68 }
69
NotifyAboutFinishedThread(const oslInterlockedCount nThreadID)70 void ThreadManager::NotifyAboutFinishedThread( const oslInterlockedCount nThreadID )
71 {
72 RemoveThread( nThreadID, true );
73 }
74
AddThread(const rtl::Reference<ObservableThread> & rThread)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
RemoveThread(const oslInterlockedCount nThreadID,const bool bThreadFinished)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
StartWaitingThread()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
StartThread(const tThreadData & rThreadData)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
IMPL_LINK(ThreadManager,TryToStartNewThread,Timer *,EMPTYARG)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
ResumeStartingOfThreads()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