source: trunk/src/kernel/qthread_pm.cpp

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

Kernel/Tools: Improved OS/2 exception handling:

  • Moved the excpetion handler code from the kernel module to the tools module (defines are now in qt_os2.h instead of qwindowdefs_pm.h);
  • QT_PM_NO_SYSEXCEPTIONS is renamed to QT_OS2_NO_SYSEXCEPTIONS;
  • Added the QtOS2SysXcptMainHandler stack-based class to correctly install the exception handler on the main thread, as well as provide an optional callback.
  • Property svn:keywords set to Id
File size: 10.2 KB
Line 
1/****************************************************************************
2** $Id: qthread_pm.cpp 139 2006-10-20 21:44:52Z 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#if !defined(QT_OS2_NO_SYSEXCEPTIONS)
109 // don't set the exception handler if not able to do it for the main thread
110 bool setException = QtOS2SysXcptMainHandler::installed;
111 EXCEPTIONREGISTRATIONRECORD excRegRec =
112 { 0, QtOS2SysXcptMainHandler::handler };
113 if ( setException )
114 DosSetExceptionHandler( &excRegRec );
115#endif
116
117 ( (QThread *) arg[0] )->run();
118
119 finish( (QThreadInstance *) arg[1] );
120
121#if !defined(QT_OS2_NO_SYSEXCEPTIONS)
122 if ( setException )
123 DosUnsetExceptionHandler( &excRegRec );
124#endif
125
126 return;
127}
128
129void QThreadInstance::finish( QThreadInstance *d )
130{
131 if ( ! d ) {
132#ifdef QT_CHECK_STATE
133 qWarning( "QThread: internal error: zero data for running thread." );
134#endif // QT_CHECK_STATE
135 return;
136 }
137
138 QMutexLocker locker( d->mutex() );
139 d->running = FALSE;
140 d->finished = TRUE;
141 d->args[0] = d->args[1] = 0;
142
143 QThreadStorageData::finish( d->thread_storage );
144 d->thread_storage = 0;
145 d->thread_id = 0;
146
147 if ( d->orphan ) {
148 d->deinit();
149 delete d;
150 }
151}
152
153QMutex *QThreadInstance::mutex() const
154{
155 return qt_thread_mutexpool ? qt_thread_mutexpool->get( (void *) this ) : 0;
156}
157
158void QThreadInstance::terminate()
159{
160 PTIB ptib;
161 DosGetInfoBlocks( &ptib, NULL );
162 if ( ptib->tib_ptib2->tib2_ultid == thread_id ) {
163#ifdef QT_CHECK_STATE
164 qWarning( "QThread: internal error: thread cannot terminate itself." );
165#endif // QT_CHECK_STATE
166 return;
167 }
168
169 /*
170 delete the thread storage *after* the thread has been
171 terminated. we could end up deleting the thread's data while it
172 is accessing it (but before the thread stops), which results in
173 a crash.
174 */
175 void **storage = thread_storage;
176 thread_storage = 0;
177
178 running = FALSE;
179 finished = TRUE;
180 args[0] = args[1] = 0;
181
182 if ( orphan ) {
183 deinit();
184 delete this;
185 }
186
187 DosKillThread( thread_id );
188 thread_id = 0;
189
190 QThreadStorageData::finish( storage );
191}
192
193
194/**************************************************************************
195 ** QThread
196 *************************************************************************/
197
198Qt::HANDLE QThread::currentThread()
199{
200 PTIB ptib;
201 DosGetInfoBlocks( &ptib, NULL );
202 return (Qt::HANDLE) ptib->tib_ptib2->tib2_ultid;
203}
204
205void QThread::initialize()
206{
207 if ( ! qt_global_mutexpool )
208 qt_global_mutexpool = new QMutexPool( TRUE, 73 );
209 if ( ! qt_thread_mutexpool )
210 qt_thread_mutexpool = new QMutexPool( FALSE, 127 );
211}
212
213void QThread::cleanup()
214{
215 delete qt_global_mutexpool;
216 delete qt_thread_mutexpool;
217 qt_global_mutexpool = 0;
218 qt_thread_mutexpool = 0;
219
220 QThreadInstance::finish(&main_instance);
221}
222
223void QThread::sleep( unsigned long secs )
224{
225 DosSleep( secs * 1000 );
226}
227
228void QThread::msleep( unsigned long msecs )
229{
230 DosSleep( msecs );
231}
232
233void QThread::usleep( unsigned long usecs )
234{
235 DosSleep( ( usecs / 1000 ) + 1 );
236}
237
238
239void QThread::start(Priority priority)
240{
241 QMutexLocker locker( d->mutex() );
242
243 if ( d->running && !d->finished ) {
244#ifdef QT_CHECK_RANGE
245 qWarning( "Thread is already running" );
246#endif
247 wait();
248 }
249
250 d->running = TRUE;
251 d->finished = FALSE;
252 d->args[0] = this;
253 d->args[1] = d;
254
255 /*
256 NOTE: we create the thread in the suspended state, set the
257 priority and then resume the thread.
258
259 since threads are created with normal priority by default, we
260 could get into a case where a thread (with priority less than
261 NormalPriority) tries to create a new thread (also with priority
262 less than NormalPriority), but the newly created thread preempts
263 its 'parent' and runs at normal priority.
264 */
265 int stacksize = d->stacksize ? d->stacksize : THREAD_DEF_STACK_SIZE;
266 int tid = _beginthread( QThreadInstance::start, NULL, stacksize, d->args );
267 d->thread_id = tid != -1 ? (TID) tid : 0;
268
269 if ( !d->thread_id ) {
270#ifdef QT_CHECK_STATE
271 qWarning( "Failed to create thread\n\tError code %d - %s", errno, strerror( errno ) );
272#endif
273 d->running = FALSE;
274 d->finished = TRUE;
275 d->args[0] = d->args[1] = 0;
276 return;
277 }
278
279 ULONG prioClass = 0;
280 LONG prioDelta = 0;
281 switch (priority) {
282 case IdlePriority:
283 prioClass = PRTYC_IDLETIME;
284 prioDelta = PRTYD_MINIMUM;
285 break;
286
287 case LowestPriority:
288 prioClass = PRTYC_IDLETIME;
289 break;
290
291 case LowPriority:
292 prioClass = PRTYC_IDLETIME;
293 prioDelta = PRTYD_MAXIMUM;
294 break;
295
296 case NormalPriority:
297 prioClass = PRTYC_REGULAR;
298 break;
299
300 case HighPriority:
301 prioClass = PRTYC_REGULAR;
302 prioDelta = PRTYD_MAXIMUM;
303 break;
304
305 case HighestPriority:
306 prioClass = PRTYC_TIMECRITICAL;
307 break;
308
309 case TimeCriticalPriority:
310 prioClass = PRTYC_TIMECRITICAL;
311 prioDelta = PRTYD_MAXIMUM;
312 break;
313
314 case InheritPriority:
315 default:
316 PTIB ptib;
317 DosGetInfoBlocks( &ptib, NULL );
318 prioClass = (ptib->tib_ptib2->tib2_ulpri >> 8) & 0xFF;
319 prioDelta = (ptib->tib_ptib2->tib2_ulpri) & 0xFF;
320 break;
321 }
322
323 APIRET rc = DosSetPriority( PRTYS_THREAD, prioClass, prioDelta, d->thread_id );
324 if ( rc ) {
325#ifdef QT_CHECK_STATE
326 qSystemWarning( "Failed to set thread priority", rc );
327#endif
328 }
329}
330
331void QThread::start()
332{
333 start(InheritPriority);
334}
335
336bool QThread::wait( unsigned long time )
337{
338 PTIB ptib;
339 DosGetInfoBlocks( &ptib, NULL );
340
341 QMutexLocker locker(d->mutex());
342
343 if ( d->thread_id == ptib->tib_ptib2->tib2_ultid ) {
344#ifdef QT_CHECK_RANGE
345 qWarning( "Thread tried to wait on itself" );
346#endif
347 return FALSE;
348 }
349 if ( d->finished || !d->running )
350 return TRUE;
351
352 ++d->waiters;
353 locker.mutex()->unlock();
354
355 bool ret = TRUE;
356 TID tid = d->thread_id;
357 APIRET rc = 0;
358 if (time == ULONG_MAX ) {
359 rc = DosWaitThread( &tid, DCWW_WAIT );
360 } else {
361 ULONG sleep;
362 do {
363 sleep = time > THREAD_WAIT_INTERVAL ? THREAD_WAIT_INTERVAL : time;
364 DosSleep( sleep );
365 rc = DosWaitThread( &tid, DCWW_NOWAIT );
366 if ( rc != ERROR_THREAD_NOT_TERMINATED )
367 break;
368 if ( d->finished || !d->running ) {
369 rc = 0;
370 break;
371 }
372 time -= sleep;
373 } while ( time );
374 }
375 if ( rc && rc != ERROR_INVALID_THREADID ) {
376#ifdef QT_CHECK_RANGE
377 qSystemWarning( "Thread wait failure", rc );
378#endif
379 ret = FALSE;
380 }
381
382 locker.mutex()->lock();
383 --d->waiters;
384
385 return ret;
386}
387
388void QThread::exit()
389{
390 QThreadInstance *d = QThreadInstance::current();
391
392 if ( ! d ) {
393#ifdef QT_CHECK_STATE
394 qWarning( "QThread::exit() called without a QThread instance." );
395#endif // QT_CHECK_STATE
396
397 _endthread();
398 return;
399 }
400
401 QThreadInstance::finish(d);
402 _endthread();
403}
404
405
406#endif // QT_THREAD_SUPPORT
Note: See TracBrowser for help on using the repository browser.