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