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

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

Kernel: Added the Qt-wide OS/2 system exception handler (see ticket:33 for details). It may be disabled by defining QT_PM_NO_SYSEXCEPTIONS when building Qt.

  • Property svn:keywords set to Id
File size: 10.6 KB
Line 
1/****************************************************************************
2** $Id: qthread_pm.cpp 136 2006-10-18 21:58:35Z 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#if !defined(QT_PM_NO_SYSEXCEPTIONS)
43extern // defined in qsysxcpt_pm.cpp
44ULONG APIENTRY qt_exceptionHandler( PEXCEPTIONREPORTRECORD pReportRec,
45 PEXCEPTIONREGISTRATIONRECORD pRegRec,
46 PCONTEXTRECORD pContextRec,
47 PVOID pv );
48extern ERR qt_libcExceptionHandler; // defined in qapplication_pm.cpp
49#endif
50
51#include "qthread.h"
52#include <private/qthreadinstance_p.h>
53#include <private/qmutexpool_p.h>
54#include "qthreadstorage.h"
55
56#include <private/qcriticalsection_p.h>
57
58#include <stdlib.h>
59
60static QThreadInstance main_instance = {
61 0, { 0, &main_instance }, 0, 0, 1, 0, 0, 0
62};
63
64
65static QMutexPool *qt_thread_mutexpool = 0;
66
67#define LocalStorage (*_threadstore())
68
69enum
70{
71 // OS/2 doesn't support specifying a maximum time to wait for a thread
72 // to end other than infininty, so we use a loop containing of wait
73 // intervals until the thread has ended or the maximum time specified
74 // by the caller has expired (in ms)
75 THREAD_WAIT_INTERVAL = 1000,
76 // default thread stack size (in bytes)
77 THREAD_DEF_STACK_SIZE = 0x200000, // 2 MB
78};
79
80/**************************************************************************
81 ** QThreadInstance
82 *************************************************************************/
83
84QThreadInstance *QThreadInstance::current()
85{
86 QThreadInstance *ret = (QThreadInstance *) LocalStorage;
87 if ( ! ret ) return &main_instance;
88 return ret;
89}
90
91void QThreadInstance::init(unsigned int stackSize)
92{
93 stacksize = stackSize;
94 args[0] = args[1] = 0;
95 thread_storage = 0;
96 finished = FALSE;
97 running = FALSE;
98 orphan = FALSE;
99
100 thread_id = 0;
101 waiters = 0;
102
103 // threads have not been initialized yet, do it now
104 if ( ! qt_thread_mutexpool ) QThread::initialize();
105}
106
107void QThreadInstance::deinit()
108{
109}
110
111void _System QThreadInstance::start( void * _arg )
112{
113 void **arg = (void **) _arg;
114
115 LocalStorage = arg [1];
116
117#if !defined(QT_PM_NO_SYSEXCEPTIONS)
118 // don't set the exception handler if not able to do it for main thread
119 bool setException = qt_libcExceptionHandler != NULL;
120 EXCEPTIONREGISTRATIONRECORD excRegRec = { 0, qt_exceptionHandler };
121 if ( setException )
122 DosSetExceptionHandler( &excRegRec );
123#endif
124
125 ( (QThread *) arg[0] )->run();
126
127 finish( (QThreadInstance *) arg[1] );
128
129#if !defined(QT_PM_NO_SYSEXCEPTIONS)
130 if ( setException )
131 DosUnsetExceptionHandler( &excRegRec );
132#endif
133
134 return;
135}
136
137void QThreadInstance::finish( QThreadInstance *d )
138{
139 if ( ! d ) {
140#ifdef QT_CHECK_STATE
141 qWarning( "QThread: internal error: zero data for running thread." );
142#endif // QT_CHECK_STATE
143 return;
144 }
145
146 QMutexLocker locker( d->mutex() );
147 d->running = FALSE;
148 d->finished = TRUE;
149 d->args[0] = d->args[1] = 0;
150
151 QThreadStorageData::finish( d->thread_storage );
152 d->thread_storage = 0;
153 d->thread_id = 0;
154
155 if ( d->orphan ) {
156 d->deinit();
157 delete d;
158 }
159}
160
161QMutex *QThreadInstance::mutex() const
162{
163 return qt_thread_mutexpool ? qt_thread_mutexpool->get( (void *) this ) : 0;
164}
165
166void QThreadInstance::terminate()
167{
168 PTIB ptib;
169 DosGetInfoBlocks( &ptib, NULL );
170 if ( ptib->tib_ptib2->tib2_ultid == thread_id ) {
171#ifdef QT_CHECK_STATE
172 qWarning( "QThread: internal error: thread cannot terminate itself." );
173#endif // QT_CHECK_STATE
174 return;
175 }
176
177 /*
178 delete the thread storage *after* the thread has been
179 terminated. we could end up deleting the thread's data while it
180 is accessing it (but before the thread stops), which results in
181 a crash.
182 */
183 void **storage = thread_storage;
184 thread_storage = 0;
185
186 running = FALSE;
187 finished = TRUE;
188 args[0] = args[1] = 0;
189
190 if ( orphan ) {
191 deinit();
192 delete this;
193 }
194
195 DosKillThread( thread_id );
196 thread_id = 0;
197
198 QThreadStorageData::finish( storage );
199}
200
201
202/**************************************************************************
203 ** QThread
204 *************************************************************************/
205
206Qt::HANDLE QThread::currentThread()
207{
208 PTIB ptib;
209 DosGetInfoBlocks( &ptib, NULL );
210 return (Qt::HANDLE) ptib->tib_ptib2->tib2_ultid;
211}
212
213void QThread::initialize()
214{
215 if ( ! qt_global_mutexpool )
216 qt_global_mutexpool = new QMutexPool( TRUE, 73 );
217 if ( ! qt_thread_mutexpool )
218 qt_thread_mutexpool = new QMutexPool( FALSE, 127 );
219}
220
221void QThread::cleanup()
222{
223 delete qt_global_mutexpool;
224 delete qt_thread_mutexpool;
225 qt_global_mutexpool = 0;
226 qt_thread_mutexpool = 0;
227
228 QThreadInstance::finish(&main_instance);
229}
230
231void QThread::sleep( unsigned long secs )
232{
233 DosSleep( secs * 1000 );
234}
235
236void QThread::msleep( unsigned long msecs )
237{
238 DosSleep( msecs );
239}
240
241void QThread::usleep( unsigned long usecs )
242{
243 DosSleep( ( usecs / 1000 ) + 1 );
244}
245
246
247void QThread::start(Priority priority)
248{
249 QMutexLocker locker( d->mutex() );
250
251 if ( d->running && !d->finished ) {
252#ifdef QT_CHECK_RANGE
253 qWarning( "Thread is already running" );
254#endif
255 wait();
256 }
257
258 d->running = TRUE;
259 d->finished = FALSE;
260 d->args[0] = this;
261 d->args[1] = d;
262
263 /*
264 NOTE: we create the thread in the suspended state, set the
265 priority and then resume the thread.
266
267 since threads are created with normal priority by default, we
268 could get into a case where a thread (with priority less than
269 NormalPriority) tries to create a new thread (also with priority
270 less than NormalPriority), but the newly created thread preempts
271 its 'parent' and runs at normal priority.
272 */
273 int stacksize = d->stacksize ? d->stacksize : THREAD_DEF_STACK_SIZE;
274 int tid = _beginthread( QThreadInstance::start, NULL, stacksize, d->args );
275 d->thread_id = tid != -1 ? (TID) tid : 0;
276
277 if ( !d->thread_id ) {
278#ifdef QT_CHECK_STATE
279 qWarning( "Failed to create thread\n\tError code %d - %s", errno, strerror( errno ) );
280#endif
281 d->running = FALSE;
282 d->finished = TRUE;
283 d->args[0] = d->args[1] = 0;
284 return;
285 }
286
287 ULONG prioClass = 0;
288 LONG prioDelta = 0;
289 switch (priority) {
290 case IdlePriority:
291 prioClass = PRTYC_IDLETIME;
292 prioDelta = PRTYD_MINIMUM;
293 break;
294
295 case LowestPriority:
296 prioClass = PRTYC_IDLETIME;
297 break;
298
299 case LowPriority:
300 prioClass = PRTYC_IDLETIME;
301 prioDelta = PRTYD_MAXIMUM;
302 break;
303
304 case NormalPriority:
305 prioClass = PRTYC_REGULAR;
306 break;
307
308 case HighPriority:
309 prioClass = PRTYC_REGULAR;
310 prioDelta = PRTYD_MAXIMUM;
311 break;
312
313 case HighestPriority:
314 prioClass = PRTYC_TIMECRITICAL;
315 break;
316
317 case TimeCriticalPriority:
318 prioClass = PRTYC_TIMECRITICAL;
319 prioDelta = PRTYD_MAXIMUM;
320 break;
321
322 case InheritPriority:
323 default:
324 PTIB ptib;
325 DosGetInfoBlocks( &ptib, NULL );
326 prioClass = (ptib->tib_ptib2->tib2_ulpri >> 8) & 0xFF;
327 prioDelta = (ptib->tib_ptib2->tib2_ulpri) & 0xFF;
328 break;
329 }
330
331 APIRET rc = DosSetPriority( PRTYS_THREAD, prioClass, prioDelta, d->thread_id );
332 if ( rc ) {
333#ifdef QT_CHECK_STATE
334 qSystemWarning( "Failed to set thread priority", rc );
335#endif
336 }
337}
338
339void QThread::start()
340{
341 start(InheritPriority);
342}
343
344bool QThread::wait( unsigned long time )
345{
346 PTIB ptib;
347 DosGetInfoBlocks( &ptib, NULL );
348
349 QMutexLocker locker(d->mutex());
350
351 if ( d->thread_id == ptib->tib_ptib2->tib2_ultid ) {
352#ifdef QT_CHECK_RANGE
353 qWarning( "Thread tried to wait on itself" );
354#endif
355 return FALSE;
356 }
357 if ( d->finished || !d->running )
358 return TRUE;
359
360 ++d->waiters;
361 locker.mutex()->unlock();
362
363 bool ret = TRUE;
364 TID tid = d->thread_id;
365 APIRET rc = 0;
366 if (time == ULONG_MAX ) {
367 rc = DosWaitThread( &tid, DCWW_WAIT );
368 } else {
369 ULONG sleep;
370 do {
371 sleep = time > THREAD_WAIT_INTERVAL ? THREAD_WAIT_INTERVAL : time;
372 DosSleep( sleep );
373 rc = DosWaitThread( &tid, DCWW_NOWAIT );
374 if ( rc != ERROR_THREAD_NOT_TERMINATED )
375 break;
376 if ( d->finished || !d->running ) {
377 rc = 0;
378 break;
379 }
380 time -= sleep;
381 } while ( time );
382 }
383 if ( rc && rc != ERROR_INVALID_THREADID ) {
384#ifdef QT_CHECK_RANGE
385 qSystemWarning( "Thread wait failure", rc );
386#endif
387 ret = FALSE;
388 }
389
390 locker.mutex()->lock();
391 --d->waiters;
392
393 return ret;
394}
395
396void QThread::exit()
397{
398 QThreadInstance *d = QThreadInstance::current();
399
400 if ( ! d ) {
401#ifdef QT_CHECK_STATE
402 qWarning( "QThread::exit() called without a QThread instance." );
403#endif // QT_CHECK_STATE
404
405 _endthread();
406 return;
407 }
408
409 QThreadInstance::finish(d);
410 _endthread();
411}
412
413
414#endif // QT_THREAD_SUPPORT
Note: See TracBrowser for help on using the repository browser.