| 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 |
|
|---|
| 51 | static QThreadInstance main_instance = {
|
|---|
| 52 | 0, { 0, &main_instance }, 0, 0, 1, 0, 0, 0
|
|---|
| 53 | };
|
|---|
| 54 |
|
|---|
| 55 |
|
|---|
| 56 | static 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.
|
|---|
| 64 | static const ULONG THREAD_WAIT_INTERVAL = 1000;
|
|---|
| 65 |
|
|---|
| 66 | /**************************************************************************
|
|---|
| 67 | ** QThreadInstance
|
|---|
| 68 | *************************************************************************/
|
|---|
| 69 |
|
|---|
| 70 | QThreadInstance *QThreadInstance::current()
|
|---|
| 71 | {
|
|---|
| 72 | QThreadInstance *ret = (QThreadInstance *) LocalStorage;
|
|---|
| 73 | if ( ! ret ) return &main_instance;
|
|---|
| 74 | return ret;
|
|---|
| 75 | }
|
|---|
| 76 |
|
|---|
| 77 | void 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 |
|
|---|
| 93 | void QThreadInstance::deinit()
|
|---|
| 94 | {
|
|---|
| 95 | }
|
|---|
| 96 |
|
|---|
| 97 | void _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 |
|
|---|
| 110 | void 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 |
|
|---|
| 134 | QMutex *QThreadInstance::mutex() const
|
|---|
| 135 | {
|
|---|
| 136 | return qt_thread_mutexpool ? qt_thread_mutexpool->get( (void *) this ) : 0;
|
|---|
| 137 | }
|
|---|
| 138 |
|
|---|
| 139 | void 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 |
|
|---|
| 179 | Qt::HANDLE QThread::currentThread()
|
|---|
| 180 | {
|
|---|
| 181 | PTIB ptib;
|
|---|
| 182 | DosGetInfoBlocks( &ptib, NULL );
|
|---|
| 183 | return (Qt::HANDLE) ptib->tib_ptib2->tib2_ultid;
|
|---|
| 184 | }
|
|---|
| 185 |
|
|---|
| 186 | void 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 |
|
|---|
| 194 | void 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 |
|
|---|
| 204 | void QThread::sleep( unsigned long secs )
|
|---|
| 205 | {
|
|---|
| 206 | DosSleep( secs * 1000 );
|
|---|
| 207 | }
|
|---|
| 208 |
|
|---|
| 209 | void QThread::msleep( unsigned long msecs )
|
|---|
| 210 | {
|
|---|
| 211 | DosSleep( msecs );
|
|---|
| 212 | }
|
|---|
| 213 |
|
|---|
| 214 | void QThread::usleep( unsigned long usecs )
|
|---|
| 215 | {
|
|---|
| 216 | DosSleep( ( usecs / 1000 ) + 1 );
|
|---|
| 217 | }
|
|---|
| 218 |
|
|---|
| 219 |
|
|---|
| 220 | void 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 |
|
|---|
| 312 | void QThread::start()
|
|---|
| 313 | {
|
|---|
| 314 | start(InheritPriority);
|
|---|
| 315 | }
|
|---|
| 316 |
|
|---|
| 317 | bool 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 |
|
|---|
| 369 | void 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
|
|---|