source: trunk/src/kernel/qthread_pm.cpp@ 125

Last change on this file since 125 was 125, checked in by dmik, 19 years ago

Kernel: Increased the default stack size for a newly created QThread from 32768 B to 2 MB (thanks to froloff for reporting)

  • Property svn:keywords set to Id
File size: 9.7 KB
Line 
1/****************************************************************************
2** $Id: qthread_pm.cpp 125 2006-09-13 11:06:01Z dmik $
3**
4** QThread class for OS/2
5**
6** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#if defined(QT_THREAD_SUPPORT)
39
40#include "qt_os2.h"
41
42#include "qthread.h"
43#include <private/qthreadinstance_p.h>
44#include <private/qmutexpool_p.h>
45#include "qthreadstorage.h"
46
47#include <private/qcriticalsection_p.h>
48
49#include <stdlib.h>
50
51static QThreadInstance main_instance = {
52 0, { 0, &main_instance }, 0, 0, 1, 0, 0, 0
53};
54
55
56static QMutexPool *qt_thread_mutexpool = 0;
57
58#define LocalStorage (*_threadstore())
59
60enum
61{
62 // OS/2 doesn't support specifying a maximum time to wait for a thread
63 // to end other than infininty, so we use a loop containing of wait
64 // intervals until the thread has ended or the maximum time specified
65 // by the caller has expired (in ms)
66 THREAD_WAIT_INTERVAL = 1000,
67 // default thread stack size (in bytes)
68 THREAD_DEF_STACK_SIZE = 0x200000, // 2 MB
69};
70
71/**************************************************************************
72 ** QThreadInstance
73 *************************************************************************/
74
75QThreadInstance *QThreadInstance::current()
76{
77 QThreadInstance *ret = (QThreadInstance *) LocalStorage;
78 if ( ! ret ) return &main_instance;
79 return ret;
80}
81
82void QThreadInstance::init(unsigned int stackSize)
83{
84 stacksize = stackSize;
85 args[0] = args[1] = 0;
86 thread_storage = 0;
87 finished = FALSE;
88 running = FALSE;
89 orphan = FALSE;
90
91 thread_id = 0;
92 waiters = 0;
93
94 // threads have not been initialized yet, do it now
95 if ( ! qt_thread_mutexpool ) QThread::initialize();
96}
97
98void QThreadInstance::deinit()
99{
100}
101
102void _System QThreadInstance::start( void * _arg )
103{
104 void **arg = (void **) _arg;
105
106 LocalStorage = arg [1];
107
108 ( (QThread *) arg[0] )->run();
109
110 finish( (QThreadInstance *) arg[1] );
111
112 return;
113}
114
115void QThreadInstance::finish( QThreadInstance *d )
116{
117 if ( ! d ) {
118#ifdef QT_CHECK_STATE
119 qWarning( "QThread: internal error: zero data for running thread." );
120#endif // QT_CHECK_STATE
121 return;
122 }
123
124 QMutexLocker locker( d->mutex() );
125 d->running = FALSE;
126 d->finished = TRUE;
127 d->args[0] = d->args[1] = 0;
128
129 QThreadStorageData::finish( d->thread_storage );
130 d->thread_storage = 0;
131 d->thread_id = 0;
132
133 if ( d->orphan ) {
134 d->deinit();
135 delete d;
136 }
137}
138
139QMutex *QThreadInstance::mutex() const
140{
141 return qt_thread_mutexpool ? qt_thread_mutexpool->get( (void *) this ) : 0;
142}
143
144void QThreadInstance::terminate()
145{
146 PTIB ptib;
147 DosGetInfoBlocks( &ptib, NULL );
148 if ( ptib->tib_ptib2->tib2_ultid == thread_id ) {
149#ifdef QT_CHECK_STATE
150 qWarning( "QThread: internal error: thread cannot terminate itself." );
151#endif // QT_CHECK_STATE
152 return;
153 }
154
155 /*
156 delete the thread storage *after* the thread has been
157 terminated. we could end up deleting the thread's data while it
158 is accessing it (but before the thread stops), which results in
159 a crash.
160 */
161 void **storage = thread_storage;
162 thread_storage = 0;
163
164 running = FALSE;
165 finished = TRUE;
166 args[0] = args[1] = 0;
167
168 if ( orphan ) {
169 deinit();
170 delete this;
171 }
172
173 DosKillThread( thread_id );
174 thread_id = 0;
175
176 QThreadStorageData::finish( storage );
177}
178
179
180/**************************************************************************
181 ** QThread
182 *************************************************************************/
183
184Qt::HANDLE QThread::currentThread()
185{
186 PTIB ptib;
187 DosGetInfoBlocks( &ptib, NULL );
188 return (Qt::HANDLE) ptib->tib_ptib2->tib2_ultid;
189}
190
191void QThread::initialize()
192{
193 if ( ! qt_global_mutexpool )
194 qt_global_mutexpool = new QMutexPool( TRUE, 73 );
195 if ( ! qt_thread_mutexpool )
196 qt_thread_mutexpool = new QMutexPool( FALSE, 127 );
197}
198
199void QThread::cleanup()
200{
201 delete qt_global_mutexpool;
202 delete qt_thread_mutexpool;
203 qt_global_mutexpool = 0;
204 qt_thread_mutexpool = 0;
205
206 QThreadInstance::finish(&main_instance);
207}
208
209void QThread::sleep( unsigned long secs )
210{
211 DosSleep( secs * 1000 );
212}
213
214void QThread::msleep( unsigned long msecs )
215{
216 DosSleep( msecs );
217}
218
219void QThread::usleep( unsigned long usecs )
220{
221 DosSleep( ( usecs / 1000 ) + 1 );
222}
223
224
225void QThread::start(Priority priority)
226{
227 QMutexLocker locker( d->mutex() );
228
229 if ( d->running && !d->finished ) {
230#ifdef QT_CHECK_RANGE
231 qWarning( "Thread is already running" );
232#endif
233 wait();
234 }
235
236 d->running = TRUE;
237 d->finished = FALSE;
238 d->args[0] = this;
239 d->args[1] = d;
240
241 /*
242 NOTE: we create the thread in the suspended state, set the
243 priority and then resume the thread.
244
245 since threads are created with normal priority by default, we
246 could get into a case where a thread (with priority less than
247 NormalPriority) tries to create a new thread (also with priority
248 less than NormalPriority), but the newly created thread preempts
249 its 'parent' and runs at normal priority.
250 */
251 int stacksize = d->stacksize ? d->stacksize : THREAD_DEF_STACK_SIZE;
252 int tid = _beginthread( QThreadInstance::start, NULL, stacksize, d->args );
253 d->thread_id = tid != -1 ? (TID) tid : 0;
254
255 if ( !d->thread_id ) {
256#ifdef QT_CHECK_STATE
257 qWarning( "Failed to create thread\n\tError code %d - %s", errno, strerror( errno ) );
258#endif
259 d->running = FALSE;
260 d->finished = TRUE;
261 d->args[0] = d->args[1] = 0;
262 return;
263 }
264
265 ULONG prioClass = 0;
266 LONG prioDelta = 0;
267 switch (priority) {
268 case IdlePriority:
269 prioClass = PRTYC_IDLETIME;
270 prioDelta = PRTYD_MINIMUM;
271 break;
272
273 case LowestPriority:
274 prioClass = PRTYC_IDLETIME;
275 break;
276
277 case LowPriority:
278 prioClass = PRTYC_IDLETIME;
279 prioDelta = PRTYD_MAXIMUM;
280 break;
281
282 case NormalPriority:
283 prioClass = PRTYC_REGULAR;
284 break;
285
286 case HighPriority:
287 prioClass = PRTYC_REGULAR;
288 prioDelta = PRTYD_MAXIMUM;
289 break;
290
291 case HighestPriority:
292 prioClass = PRTYC_TIMECRITICAL;
293 break;
294
295 case TimeCriticalPriority:
296 prioClass = PRTYC_TIMECRITICAL;
297 prioDelta = PRTYD_MAXIMUM;
298 break;
299
300 case InheritPriority:
301 default:
302 PTIB ptib;
303 DosGetInfoBlocks( &ptib, NULL );
304 prioClass = (ptib->tib_ptib2->tib2_ulpri >> 8) & 0xFF;
305 prioDelta = (ptib->tib_ptib2->tib2_ulpri) & 0xFF;
306 break;
307 }
308
309 APIRET rc = DosSetPriority( PRTYS_THREAD, prioClass, prioDelta, d->thread_id );
310 if ( rc ) {
311#ifdef QT_CHECK_STATE
312 qSystemWarning( "Failed to set thread priority", rc );
313#endif
314 }
315}
316
317void QThread::start()
318{
319 start(InheritPriority);
320}
321
322bool QThread::wait( unsigned long time )
323{
324 PTIB ptib;
325 DosGetInfoBlocks( &ptib, NULL );
326
327 QMutexLocker locker(d->mutex());
328
329 if ( d->thread_id == ptib->tib_ptib2->tib2_ultid ) {
330#ifdef QT_CHECK_RANGE
331 qWarning( "Thread tried to wait on itself" );
332#endif
333 return FALSE;
334 }
335 if ( d->finished || !d->running )
336 return TRUE;
337
338 ++d->waiters;
339 locker.mutex()->unlock();
340
341 bool ret = TRUE;
342 TID tid = d->thread_id;
343 APIRET rc = 0;
344 if (time == ULONG_MAX ) {
345 rc = DosWaitThread( &tid, DCWW_WAIT );
346 } else {
347 ULONG sleep;
348 do {
349 sleep = time > THREAD_WAIT_INTERVAL ? THREAD_WAIT_INTERVAL : time;
350 DosSleep( sleep );
351 rc = DosWaitThread( &tid, DCWW_NOWAIT );
352 if ( rc != ERROR_THREAD_NOT_TERMINATED )
353 break;
354 if ( d->finished || !d->running ) {
355 rc = 0;
356 break;
357 }
358 time -= sleep;
359 } while ( time );
360 }
361 if ( rc && rc != ERROR_INVALID_THREADID ) {
362#ifdef QT_CHECK_RANGE
363 qSystemWarning( "Thread wait failure", rc );
364#endif
365 ret = FALSE;
366 }
367
368 locker.mutex()->lock();
369 --d->waiters;
370
371 return ret;
372}
373
374void QThread::exit()
375{
376 QThreadInstance *d = QThreadInstance::current();
377
378 if ( ! d ) {
379#ifdef QT_CHECK_STATE
380 qWarning( "QThread::exit() called without a QThread instance." );
381#endif // QT_CHECK_STATE
382
383 _endthread();
384 return;
385 }
386
387 QThreadInstance::finish(d);
388 _endthread();
389}
390
391
392#endif // QT_THREAD_SUPPORT
Note: See TracBrowser for help on using the repository browser.