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

Last change on this file since 123 was 8, checked in by dmik, 20 years ago

Transferred Qt for OS/2 version 3.3.1-rc5 sources from the CVS

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