~ubuntu-branches/debian/lenny/italc/lenny

« back to all changes in this revision

Viewing changes to ica/win32/src/omnithread/nt.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mto: This revision was merged to the branch mainline in revision 5.
  • Revision ID: james.westby@ubuntu.com-20080617134654-2y5m7ki93r5c1ysf
Tags: upstream-1.0.9~rc3
ImportĀ upstreamĀ versionĀ 1.0.9~rc3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//                              Package : omnithread
 
2
// omnithread/nt.cc             Created : 6/95 tjr
 
3
//
 
4
//    Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
 
5
//
 
6
//    This file is part of the omnithread library
 
7
//
 
8
//    The omnithread library is free software; you can redistribute it and/or
 
9
//    modify it under the terms of the GNU Library General Public
 
10
//    License as published by the Free Software Foundation; either
 
11
//    version 2 of the License, or (at your option) any later version.
 
12
//
 
13
//    This library is distributed in the hope that it will be useful,
 
14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
//    Library General Public License for more details.
 
17
//
 
18
//    You should have received a copy of the GNU Library General Public
 
19
//    License along with this library; if not, write to the Free
 
20
//    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 
21
//    02111-1307, USA
 
22
//
 
23
 
 
24
//
 
25
// Implementation of OMNI thread abstraction for NT threads
 
26
//
 
27
 
 
28
#include <stdlib.h>
 
29
#include <errno.h>
 
30
#include "omnithread.h"
 
31
#include <process.h>
 
32
 
 
33
#define DB(x) // x 
 
34
//#include <iostream.h> or #include <iostream> if DB is on.
 
35
 
 
36
static void get_time_now(unsigned long* abs_sec, unsigned long* abs_nsec);
 
37
 
 
38
///////////////////////////////////////////////////////////////////////////
 
39
//
 
40
// Mutex
 
41
//
 
42
///////////////////////////////////////////////////////////////////////////
 
43
 
 
44
 
 
45
omni_mutex::omni_mutex(void)
 
46
{
 
47
    InitializeCriticalSection(&crit);
 
48
}
 
49
 
 
50
omni_mutex::~omni_mutex(void)
 
51
{
 
52
    DeleteCriticalSection(&crit);
 
53
}
 
54
 
 
55
void
 
56
omni_mutex::lock(void)
 
57
{
 
58
    EnterCriticalSection(&crit);
 
59
}
 
60
 
 
61
void
 
62
omni_mutex::unlock(void)
 
63
{
 
64
    LeaveCriticalSection(&crit);
 
65
}
 
66
 
 
67
 
 
68
 
 
69
///////////////////////////////////////////////////////////////////////////
 
70
//
 
71
// Condition variable
 
72
//
 
73
///////////////////////////////////////////////////////////////////////////
 
74
 
 
75
 
 
76
//
 
77
// Condition variables are tricky to implement using NT synchronisation
 
78
// primitives, since none of them have the atomic "release mutex and wait to be
 
79
// signalled" which is central to the idea of a condition variable.  To get
 
80
// around this the solution is to record which threads are waiting and
 
81
// explicitly wake up those threads.
 
82
//
 
83
// Here we implement a condition variable using a list of waiting threads
 
84
// (protected by a critical section), and a per-thread semaphore (which
 
85
// actually only needs to be a binary semaphore).
 
86
//
 
87
// To wait on the cv, a thread puts itself on the list of waiting threads for
 
88
// that cv, then releases the mutex and waits on its own personal semaphore.  A
 
89
// signalling thread simply takes a thread from the head of the list and kicks
 
90
// that thread's semaphore.  Broadcast is simply implemented by kicking the
 
91
// semaphore of each waiting thread.
 
92
//
 
93
// The only other tricky part comes when a thread gets a timeout from a timed
 
94
// wait on its semaphore.  Between returning with a timeout from the wait and
 
95
// entering the critical section, a signalling thread could get in, kick the
 
96
// waiting thread's semaphore and remove it from the list.  If this happens,
 
97
// the waiting thread's semaphore is now out of step so it needs resetting, and
 
98
// the thread should indicate that it was signalled rather than that it timed
 
99
// out.
 
100
//
 
101
// It is possible that the thread calling wait or timedwait is not a
 
102
// omni_thread. In this case we have to provide a temporary data structure,
 
103
// i.e. for the duration of the call, for the thread to link itself on the
 
104
// list of waiting threads. _internal_omni_thread_dummy provides such
 
105
// a data structure and _internal_omni_thread_helper is a helper class to
 
106
// deal with this special case for wait() and timedwait(). Once created,
 
107
// the _internal_omni_thread_dummy is cached for use by the next wait() or
 
108
// timedwait() call from a non-omni_thread. This is probably worth doing
 
109
// because creating a Semaphore is quite heavy weight.
 
110
 
 
111
class _internal_omni_thread_helper;
 
112
 
 
113
class _internal_omni_thread_dummy : public omni_thread {
 
114
public:
 
115
  inline _internal_omni_thread_dummy() : next(0) { }
 
116
  inline ~_internal_omni_thread_dummy() { }
 
117
  friend class _internal_omni_thread_helper;
 
118
private:
 
119
  _internal_omni_thread_dummy* next;
 
120
};
 
121
 
 
122
class _internal_omni_thread_helper {
 
123
public:
 
124
  inline _internal_omni_thread_helper()  { 
 
125
    d = 0;
 
126
    t = omni_thread::self();
 
127
    if (!t) {
 
128
      omni_mutex_lock sync(cachelock);
 
129
      if (cache) {
 
130
        d = cache;
 
131
        cache = cache->next;
 
132
      }
 
133
      else {
 
134
        d = new _internal_omni_thread_dummy;
 
135
      }
 
136
      t = d;
 
137
    }
 
138
  }
 
139
  inline ~_internal_omni_thread_helper() { 
 
140
    if (d) {
 
141
      omni_mutex_lock sync(cachelock);
 
142
      d->next = cache;
 
143
      cache = d;
 
144
    }
 
145
  }
 
146
  inline operator omni_thread* () { return t; }
 
147
  inline omni_thread* operator->() { return t; }
 
148
 
 
149
  static _internal_omni_thread_dummy* cache;
 
150
  static omni_mutex                   cachelock;
 
151
 
 
152
private:
 
153
  _internal_omni_thread_dummy* d;
 
154
  omni_thread*                 t;
 
155
};
 
156
 
 
157
_internal_omni_thread_dummy* _internal_omni_thread_helper::cache = 0;
 
158
omni_mutex                   _internal_omni_thread_helper::cachelock;
 
159
 
 
160
 
 
161
omni_condition::omni_condition(omni_mutex* m) : mutex(m)
 
162
{
 
163
    InitializeCriticalSection(&crit);
 
164
    waiting_head = waiting_tail = NULL;
 
165
}
 
166
 
 
167
 
 
168
omni_condition::~omni_condition(void)
 
169
{
 
170
    DeleteCriticalSection(&crit);
 
171
    DB( if (waiting_head != NULL) {
 
172
        cerr << "omni_condition::~omni_condition: list of waiting threads "
 
173
             << "is not empty\n";
 
174
    } )
 
175
}
 
176
 
 
177
 
 
178
void
 
179
omni_condition::wait(void)
 
180
{
 
181
    _internal_omni_thread_helper me;
 
182
 
 
183
    EnterCriticalSection(&crit);
 
184
 
 
185
    me->cond_next = NULL;
 
186
    me->cond_prev = waiting_tail;
 
187
    if (waiting_head == NULL)
 
188
        waiting_head = me;
 
189
    else
 
190
        waiting_tail->cond_next = me;
 
191
    waiting_tail = me;
 
192
    me->cond_waiting = TRUE;
 
193
 
 
194
    LeaveCriticalSection(&crit);
 
195
 
 
196
    mutex->unlock();
 
197
 
 
198
    DWORD result = WaitForSingleObject(me->cond_semaphore, INFINITE);
 
199
 
 
200
    mutex->lock();
 
201
 
 
202
    if (result != WAIT_OBJECT_0)
 
203
        throw omni_thread_fatal(GetLastError());
 
204
}
 
205
 
 
206
 
 
207
int
 
208
omni_condition::timedwait(unsigned long abs_sec, unsigned long abs_nsec)
 
209
{
 
210
    _internal_omni_thread_helper me;
 
211
 
 
212
    EnterCriticalSection(&crit);
 
213
 
 
214
    me->cond_next = NULL;
 
215
    me->cond_prev = waiting_tail;
 
216
    if (waiting_head == NULL)
 
217
        waiting_head = me;
 
218
    else
 
219
        waiting_tail->cond_next = me;
 
220
    waiting_tail = me;
 
221
    me->cond_waiting = TRUE;
 
222
 
 
223
    LeaveCriticalSection(&crit);
 
224
 
 
225
    mutex->unlock();
 
226
 
 
227
    unsigned long now_sec, now_nsec;
 
228
 
 
229
    get_time_now(&now_sec, &now_nsec);
 
230
 
 
231
    DWORD timeout = (abs_sec-now_sec) * 1000 + (abs_nsec-now_nsec) / 1000000;
 
232
 
 
233
    if ((abs_sec <= now_sec) && ((abs_sec < now_sec) || (abs_nsec < abs_nsec)))
 
234
        timeout = 0;
 
235
 
 
236
    DWORD result = WaitForSingleObject(me->cond_semaphore, timeout);
 
237
 
 
238
    if (result == WAIT_TIMEOUT) {
 
239
        EnterCriticalSection(&crit);
 
240
 
 
241
        if (me->cond_waiting) {
 
242
            if (me->cond_prev != NULL)
 
243
                me->cond_prev->cond_next = me->cond_next;
 
244
            else
 
245
                waiting_head = me->cond_next;
 
246
            if (me->cond_next != NULL)
 
247
                me->cond_next->cond_prev = me->cond_prev;
 
248
            else
 
249
                waiting_tail = me->cond_prev;
 
250
            me->cond_waiting = FALSE;
 
251
 
 
252
            LeaveCriticalSection(&crit);
 
253
 
 
254
            mutex->lock();
 
255
            return 0;
 
256
        }
 
257
 
 
258
        //
 
259
        // We timed out but another thread still signalled us.  Wait for
 
260
        // the semaphore (it _must_ have been signalled) to decrement it
 
261
        // again.  Return that we were signalled, not that we timed out.
 
262
        //
 
263
 
 
264
        LeaveCriticalSection(&crit);
 
265
 
 
266
        result = WaitForSingleObject(me->cond_semaphore, INFINITE);
 
267
    }
 
268
 
 
269
    if (result != WAIT_OBJECT_0)
 
270
        throw omni_thread_fatal(GetLastError());
 
271
 
 
272
    mutex->lock();
 
273
    return 1;
 
274
}
 
275
 
 
276
 
 
277
void
 
278
omni_condition::signal(void)
 
279
{
 
280
    EnterCriticalSection(&crit);
 
281
 
 
282
    if (waiting_head != NULL) {
 
283
        omni_thread* t = waiting_head;
 
284
        waiting_head = t->cond_next;
 
285
        if (waiting_head == NULL)
 
286
            waiting_tail = NULL;
 
287
        else
 
288
            waiting_head->cond_prev = NULL;
 
289
        t->cond_waiting = FALSE;
 
290
 
 
291
        if (!ReleaseSemaphore(t->cond_semaphore, 1, NULL)) {
 
292
            int rc = GetLastError();
 
293
            LeaveCriticalSection(&crit);
 
294
            throw omni_thread_fatal(rc);
 
295
        }
 
296
    }
 
297
 
 
298
    LeaveCriticalSection(&crit);
 
299
}
 
300
 
 
301
 
 
302
void
 
303
omni_condition::broadcast(void)
 
304
{
 
305
    EnterCriticalSection(&crit);
 
306
 
 
307
    while (waiting_head != NULL) {
 
308
        omni_thread* t = waiting_head;
 
309
        waiting_head = t->cond_next;
 
310
        if (waiting_head == NULL)
 
311
            waiting_tail = NULL;
 
312
        else
 
313
            waiting_head->cond_prev = NULL;
 
314
        t->cond_waiting = FALSE;
 
315
 
 
316
        if (!ReleaseSemaphore(t->cond_semaphore, 1, NULL)) {
 
317
            int rc = GetLastError();
 
318
            LeaveCriticalSection(&crit);
 
319
            throw omni_thread_fatal(rc);
 
320
        }
 
321
    }
 
322
 
 
323
    LeaveCriticalSection(&crit);
 
324
}
 
325
 
 
326
 
 
327
 
 
328
///////////////////////////////////////////////////////////////////////////
 
329
//
 
330
// Counting semaphore
 
331
//
 
332
///////////////////////////////////////////////////////////////////////////
 
333
 
 
334
 
 
335
#define SEMAPHORE_MAX 0x7fffffff
 
336
 
 
337
 
 
338
omni_semaphore::omni_semaphore(unsigned int initial)
 
339
{
 
340
    nt_sem = CreateSemaphore(NULL, initial, SEMAPHORE_MAX, NULL);
 
341
 
 
342
    if (nt_sem == NULL) {
 
343
      DB( cerr << "omni_semaphore::omni_semaphore: CreateSemaphore error "
 
344
             << GetLastError() << endl );
 
345
      throw omni_thread_fatal(GetLastError());
 
346
    }
 
347
}
 
348
 
 
349
 
 
350
omni_semaphore::~omni_semaphore(void)
 
351
{
 
352
  if (!CloseHandle(nt_sem)) {
 
353
    DB( cerr << "omni_semaphore::~omni_semaphore: CloseHandle error "
 
354
             << GetLastError() << endl );
 
355
    throw omni_thread_fatal(GetLastError());
 
356
  }
 
357
}
 
358
 
 
359
 
 
360
void
 
361
omni_semaphore::wait(void)
 
362
{
 
363
    if (WaitForSingleObject(nt_sem, INFINITE) != WAIT_OBJECT_0)
 
364
        throw omni_thread_fatal(GetLastError());
 
365
}
 
366
 
 
367
 
 
368
int
 
369
omni_semaphore::trywait(void)
 
370
{
 
371
    switch (WaitForSingleObject(nt_sem, 0)) {
 
372
 
 
373
    case WAIT_OBJECT_0:
 
374
        return 1;
 
375
    case WAIT_TIMEOUT:
 
376
        return 0;
 
377
    }
 
378
 
 
379
    throw omni_thread_fatal(GetLastError());
 
380
    return 0; /* keep msvc++ happy */
 
381
}
 
382
 
 
383
 
 
384
void
 
385
omni_semaphore::post(void)
 
386
{
 
387
    if (!ReleaseSemaphore(nt_sem, 1, NULL))
 
388
        throw omni_thread_fatal(GetLastError());
 
389
}
 
390
 
 
391
 
 
392
 
 
393
///////////////////////////////////////////////////////////////////////////
 
394
//
 
395
// Thread
 
396
//
 
397
///////////////////////////////////////////////////////////////////////////
 
398
 
 
399
 
 
400
//
 
401
// Static variables
 
402
//
 
403
 
 
404
int omni_thread::init_t::count = 0;
 
405
 
 
406
omni_mutex* omni_thread::next_id_mutex;
 
407
int omni_thread::next_id = 0;
 
408
static DWORD self_tls_index;
 
409
 
 
410
//
 
411
// Initialisation function (gets called before any user code).
 
412
//
 
413
 
 
414
omni_thread::init_t::init_t(void)
 
415
{
 
416
    if (count++ != 0)   // only do it once however many objects get created.
 
417
        return;
 
418
 
 
419
    DB(cerr << "omni_thread::init: NT implementation initialising\n");
 
420
 
 
421
    self_tls_index = TlsAlloc();
 
422
 
 
423
    if (self_tls_index == 0xffffffff)
 
424
        throw omni_thread_fatal(GetLastError());
 
425
 
 
426
    next_id_mutex = new omni_mutex;
 
427
 
 
428
    //
 
429
    // Create object for this (i.e. initial) thread.
 
430
    //
 
431
 
 
432
    omni_thread* t = new omni_thread;
 
433
 
 
434
    t->_state = STATE_RUNNING;
 
435
 
 
436
    if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
 
437
                         GetCurrentProcess(), &t->handle,
 
438
                         0, FALSE, DUPLICATE_SAME_ACCESS))
 
439
        throw omni_thread_fatal(GetLastError());
 
440
 
 
441
    t->nt_id = GetCurrentThreadId();
 
442
 
 
443
    DB(cerr << "initial thread " << t->id() << " NT thread id " << t->nt_id
 
444
       << endl);
 
445
 
 
446
    if (!TlsSetValue(self_tls_index, (LPVOID)t))
 
447
        throw omni_thread_fatal(GetLastError());
 
448
 
 
449
    if (!SetThreadPriority(t->handle, nt_priority(PRIORITY_NORMAL)))
 
450
        throw omni_thread_fatal(GetLastError());
 
451
}
 
452
 
 
453
//
 
454
// Wrapper for thread creation.
 
455
//
 
456
 
 
457
extern "C" 
 
458
unsigned __stdcall
 
459
omni_thread_wrapper(void* ptr)
 
460
{
 
461
    omni_thread* me = (omni_thread*)ptr;
 
462
 
 
463
    DB(cerr << "omni_thread_wrapper: thread " << me->id()
 
464
       << " started\n");
 
465
 
 
466
    if (!TlsSetValue(self_tls_index, (LPVOID)me))
 
467
        throw omni_thread_fatal(GetLastError());
 
468
 
 
469
    //
 
470
    // Now invoke the thread function with the given argument.
 
471
    //
 
472
 
 
473
    if (me->fn_void != NULL) {
 
474
        (*me->fn_void)(me->thread_arg);
 
475
        omni_thread::exit();
 
476
    }
 
477
 
 
478
    if (me->fn_ret != NULL) {
 
479
        void* return_value = (*me->fn_ret)(me->thread_arg);
 
480
        omni_thread::exit(return_value);
 
481
    }
 
482
 
 
483
    if (me->detached) {
 
484
        me->run(me->thread_arg);
 
485
        omni_thread::exit();
 
486
    } else {
 
487
        void* return_value = me->run_undetached(me->thread_arg);
 
488
        omni_thread::exit(return_value);
 
489
    }
 
490
 
 
491
    // should never get here.
 
492
    return 0;
 
493
}
 
494
 
 
495
 
 
496
//
 
497
// Constructors for omni_thread - set up the thread object but don't
 
498
// start it running.
 
499
//
 
500
 
 
501
// construct a detached thread running a given function.
 
502
 
 
503
omni_thread::omni_thread(void (*fn)(void*), void* arg, priority_t pri)
 
504
{
 
505
    common_constructor(arg, pri, 1);
 
506
    fn_void = fn;
 
507
    fn_ret = NULL;
 
508
}
 
509
 
 
510
// construct an undetached thread running a given function.
 
511
 
 
512
omni_thread::omni_thread(void* (*fn)(void*), void* arg, priority_t pri)
 
513
{
 
514
    common_constructor(arg, pri, 0);
 
515
    fn_void = NULL;
 
516
    fn_ret = fn;
 
517
}
 
518
 
 
519
// construct a thread which will run either run() or run_undetached().
 
520
 
 
521
omni_thread::omni_thread(void* arg, priority_t pri)
 
522
{
 
523
    common_constructor(arg, pri, 1);
 
524
    fn_void = NULL;
 
525
    fn_ret = NULL;
 
526
}
 
527
 
 
528
// common part of all constructors.
 
529
 
 
530
void
 
531
omni_thread::common_constructor(void* arg, priority_t pri, int det)
 
532
{
 
533
    _state = STATE_NEW;
 
534
    _priority = pri;
 
535
 
 
536
    next_id_mutex->lock();
 
537
    _id = next_id++;
 
538
    next_id_mutex->unlock();
 
539
 
 
540
    thread_arg = arg;
 
541
    detached = det;     // may be altered in start_undetached()
 
542
 
 
543
    cond_semaphore = CreateSemaphore(NULL, 0, SEMAPHORE_MAX, NULL);
 
544
 
 
545
    if (cond_semaphore == NULL)
 
546
        throw omni_thread_fatal(GetLastError());
 
547
 
 
548
    cond_next = cond_prev = NULL;
 
549
    cond_waiting = FALSE;
 
550
 
 
551
    handle = NULL;
 
552
}
 
553
 
 
554
 
 
555
//
 
556
// Destructor for omni_thread.
 
557
//
 
558
 
 
559
omni_thread::~omni_thread(void)
 
560
{
 
561
    DB(cerr << "destructor called for thread " << id() << endl);
 
562
    if ((handle != NULL) && !CloseHandle(handle))
 
563
        throw omni_thread_fatal(GetLastError());
 
564
    if (!CloseHandle(cond_semaphore))
 
565
        throw omni_thread_fatal(GetLastError());
 
566
}
 
567
 
 
568
 
 
569
//
 
570
// Start the thread
 
571
//
 
572
 
 
573
void
 
574
omni_thread::start(void)
 
575
{
 
576
    omni_mutex_lock l(mutex);
 
577
 
 
578
    if (_state != STATE_NEW)
 
579
        throw omni_thread_invalid();
 
580
 
 
581
    unsigned int t;
 
582
    handle = (HANDLE)_beginthreadex(
 
583
                        NULL,
 
584
                        0,
 
585
                        omni_thread_wrapper,
 
586
                        (LPVOID)this,
 
587
                        CREATE_SUSPENDED, 
 
588
                        &t);
 
589
    nt_id = t;
 
590
    if (handle == NULL)
 
591
      throw omni_thread_fatal(GetLastError());
 
592
 
 
593
    if (!SetThreadPriority(handle, _priority))
 
594
      throw omni_thread_fatal(GetLastError());
 
595
 
 
596
    if (ResumeThread(handle) == 0xffffffff)
 
597
        throw omni_thread_fatal(GetLastError());
 
598
 
 
599
    _state = STATE_RUNNING;
 
600
}
 
601
 
 
602
 
 
603
//
 
604
// Start a thread which will run the member function run_undetached().
 
605
//
 
606
 
 
607
void
 
608
omni_thread::start_undetached(void)
 
609
{
 
610
    if ((fn_void != NULL) || (fn_ret != NULL))
 
611
        throw omni_thread_invalid();
 
612
 
 
613
    detached = 0;
 
614
    start();
 
615
}
 
616
 
 
617
 
 
618
//
 
619
// join - simply check error conditions & call WaitForSingleObject.
 
620
//
 
621
 
 
622
void
 
623
omni_thread::join(void** status)
 
624
{
 
625
    mutex.lock();
 
626
 
 
627
    if ((_state != STATE_RUNNING) && (_state != STATE_TERMINATED)) {
 
628
        mutex.unlock();
 
629
        throw omni_thread_invalid();
 
630
    }
 
631
 
 
632
    mutex.unlock();
 
633
 
 
634
    if (this == self())
 
635
        throw omni_thread_invalid();
 
636
 
 
637
    if (detached)
 
638
        throw omni_thread_invalid();
 
639
 
 
640
    DB(cerr << "omni_thread::join: doing WaitForSingleObject\n");
 
641
 
 
642
    if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0)
 
643
        throw omni_thread_fatal(GetLastError());
 
644
 
 
645
    DB(cerr << "omni_thread::join: WaitForSingleObject succeeded\n");
 
646
 
 
647
    if (status)
 
648
      *status = return_val;
 
649
 
 
650
    delete this;
 
651
}
 
652
 
 
653
 
 
654
//
 
655
// Change this thread's priority.
 
656
//
 
657
 
 
658
void
 
659
omni_thread::set_priority(priority_t pri)
 
660
{
 
661
    omni_mutex_lock l(mutex);
 
662
 
 
663
    if (_state != STATE_RUNNING)
 
664
        throw omni_thread_invalid();
 
665
 
 
666
    _priority = pri;
 
667
 
 
668
    if (!SetThreadPriority(handle, nt_priority(pri)))
 
669
        throw omni_thread_fatal(GetLastError());
 
670
}
 
671
 
 
672
 
 
673
//
 
674
// create - construct a new thread object and start it running.  Returns thread
 
675
// object if successful, null pointer if not.
 
676
//
 
677
 
 
678
// detached version
 
679
 
 
680
omni_thread*
 
681
omni_thread::create(void (*fn)(void*), void* arg, priority_t pri)
 
682
{
 
683
    omni_thread* t = new omni_thread(fn, arg, pri);
 
684
    t->start();
 
685
    return t;
 
686
}
 
687
 
 
688
// undetached version
 
689
 
 
690
omni_thread*
 
691
omni_thread::create(void* (*fn)(void*), void* arg, priority_t pri)
 
692
{
 
693
    omni_thread* t = new omni_thread(fn, arg, pri);
 
694
    t->start();
 
695
    return t;
 
696
}
 
697
 
 
698
 
 
699
//
 
700
// exit() _must_ lock the mutex even in the case of a detached thread.  This is
 
701
// because a thread may run to completion before the thread that created it has
 
702
// had a chance to get out of start().  By locking the mutex we ensure that the
 
703
// creating thread must have reached the end of start() before we delete the
 
704
// thread object.  Of course, once the call to start() returns, the user can
 
705
// still incorrectly refer to the thread object, but that's their problem.
 
706
//
 
707
 
 
708
void
 
709
omni_thread::exit(void* return_value)
 
710
{
 
711
    omni_thread* me = self();
 
712
 
 
713
    if (me)
 
714
      {
 
715
        me->mutex.lock();
 
716
 
 
717
        me->_state = STATE_TERMINATED;
 
718
 
 
719
        me->mutex.unlock();
 
720
 
 
721
        DB(cerr << "omni_thread::exit: thread " << me->id() << " detached "
 
722
           << me->detached << " return value " << return_value << endl);
 
723
 
 
724
        if (me->detached) {
 
725
          delete me;
 
726
        } else {
 
727
          me->return_val = return_value;
 
728
        }
 
729
      }
 
730
    else
 
731
      {
 
732
        DB(cerr << "omni_thread::exit: called with a non-omnithread. Exit quietly." << endl);
 
733
      }
 
734
    //   _endthreadex() does not automatically closes the thread handle.
 
735
    //   The omni_thread dtor closes the thread handle.
 
736
    _endthreadex(0);
 
737
}
 
738
 
 
739
 
 
740
omni_thread*
 
741
omni_thread::self(void)
 
742
{
 
743
    LPVOID me;
 
744
 
 
745
    me = TlsGetValue(self_tls_index);
 
746
 
 
747
    if (me == NULL) {
 
748
      DB(cerr << "omni_thread::self: called with a non-ominthread. NULL is returned." << endl);
 
749
    }
 
750
    return (omni_thread*)me;
 
751
}
 
752
 
 
753
 
 
754
void
 
755
omni_thread::yield(void)
 
756
{
 
757
    Sleep(0);
 
758
}
 
759
 
 
760
 
 
761
#define MAX_SLEEP_SECONDS (DWORD)4294966        // (2**32-2)/1000
 
762
 
 
763
void
 
764
omni_thread::sleep(unsigned long secs, unsigned long nanosecs)
 
765
{
 
766
    if (secs <= MAX_SLEEP_SECONDS) {
 
767
        Sleep(secs * 1000 + nanosecs / 1000000);
 
768
        return;
 
769
    }
 
770
 
 
771
    DWORD no_of_max_sleeps = secs / MAX_SLEEP_SECONDS;
 
772
 
 
773
    for (DWORD i = 0; i < no_of_max_sleeps; i++)
 
774
        Sleep(MAX_SLEEP_SECONDS * 1000);
 
775
 
 
776
    Sleep((secs % MAX_SLEEP_SECONDS) * 1000 + nanosecs / 1000000);
 
777
}
 
778
 
 
779
 
 
780
void
 
781
omni_thread::get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
 
782
                      unsigned long rel_sec, unsigned long rel_nsec)
 
783
{
 
784
    get_time_now(abs_sec, abs_nsec);
 
785
    *abs_nsec += rel_nsec;
 
786
    *abs_sec += rel_sec + *abs_nsec / 1000000000;
 
787
    *abs_nsec = *abs_nsec % 1000000000;
 
788
}
 
789
 
 
790
 
 
791
int
 
792
omni_thread::nt_priority(priority_t pri)
 
793
{
 
794
    switch (pri) {
 
795
 
 
796
    case PRIORITY_LOW:
 
797
        return THREAD_PRIORITY_LOWEST;
 
798
 
 
799
    case PRIORITY_NORMAL:
 
800
        return THREAD_PRIORITY_NORMAL;
 
801
 
 
802
    case PRIORITY_HIGH:
 
803
        return THREAD_PRIORITY_HIGHEST;
 
804
    }
 
805
 
 
806
    throw omni_thread_invalid();
 
807
    return 0; /* keep msvc++ happy */
 
808
}
 
809
 
 
810
 
 
811
static void
 
812
get_time_now(unsigned long* abs_sec, unsigned long* abs_nsec)
 
813
{
 
814
    static int days_in_preceding_months[12]
 
815
        = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
 
816
    static int days_in_preceding_months_leap[12]
 
817
        = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
 
818
 
 
819
    SYSTEMTIME st;
 
820
 
 
821
    GetSystemTime(&st);
 
822
    *abs_nsec = st.wMilliseconds * 1000000;
 
823
 
 
824
    // this formula should work until 1st March 2100
 
825
 
 
826
    DWORD days = ((st.wYear - 1970) * 365 + (st.wYear - 1969) / 4
 
827
                  + ((st.wYear % 4)
 
828
                     ? days_in_preceding_months[st.wMonth - 1]
 
829
                     : days_in_preceding_months_leap[st.wMonth - 1])
 
830
                  + st.wDay - 1);
 
831
 
 
832
    *abs_sec = st.wSecond + 60 * (st.wMinute + 60 * (st.wHour + 24 * days));
 
833
}