nt.cpp
上传用户:sbftbdw
上传日期:2007-01-03
资源大小:379k
文件大小:20k
源码类别:

远程控制编程

开发平台:

Visual C++

  1. // Package : omnithread
  2. // omnithread/nt.cc Created : 6/95 tjr
  3. //
  4. //    Copyright (C) 1995, 1996, 1997 Olivetti & Oracle Research Laboratory
  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. // Implementation of OMNI thread abstraction for NT threads
  25. //
  26. #include <stdlib.h>
  27. #include <errno.h>
  28. #include <omnithread.h>
  29. #include <process.h>
  30. #define DB(x) // x 
  31. //#include <iostream.h> or #include <iostream> if DB is on.
  32. static void get_time_now(unsigned long* abs_sec, unsigned long* abs_nsec);
  33. ///////////////////////////////////////////////////////////////////////////
  34. //
  35. // Mutex
  36. //
  37. ///////////////////////////////////////////////////////////////////////////
  38. omni_mutex::omni_mutex(void)
  39. {
  40.     InitializeCriticalSection(&crit);
  41. }
  42. omni_mutex::~omni_mutex(void)
  43. {
  44.     DeleteCriticalSection(&crit);
  45. }
  46. void
  47. omni_mutex::lock(void)
  48. {
  49.     EnterCriticalSection(&crit);
  50. }
  51. void
  52. omni_mutex::unlock(void)
  53. {
  54.     LeaveCriticalSection(&crit);
  55. }
  56. ///////////////////////////////////////////////////////////////////////////
  57. //
  58. // Condition variable
  59. //
  60. ///////////////////////////////////////////////////////////////////////////
  61. //
  62. // Condition variables are tricky to implement using NT synchronisation
  63. // primitives, since none of them have the atomic "release mutex and wait to be
  64. // signalled" which is central to the idea of a condition variable.  To get
  65. // around this the solution is to record which threads are waiting and
  66. // explicitly wake up those threads.
  67. //
  68. // Here we implement a condition variable using a list of waiting threads
  69. // (protected by a critical section), and a per-thread semaphore (which
  70. // actually only needs to be a binary semaphore).
  71. //
  72. // To wait on the cv, a thread puts itself on the list of waiting threads for
  73. // that cv, then releases the mutex and waits on its own personal semaphore.  A
  74. // signalling thread simply takes a thread from the head of the list and kicks
  75. // that thread's semaphore.  Broadcast is simply implemented by kicking the
  76. // semaphore of each waiting thread.
  77. //
  78. // The only other tricky part comes when a thread gets a timeout from a timed
  79. // wait on its semaphore.  Between returning with a timeout from the wait and
  80. // entering the critical section, a signalling thread could get in, kick the
  81. // waiting thread's semaphore and remove it from the list.  If this happens,
  82. // the waiting thread's semaphore is now out of step so it needs resetting, and
  83. // the thread should indicate that it was signalled rather than that it timed
  84. // out.
  85. //
  86. // It is possible that the thread calling wait or timedwait is not a
  87. // omni_thread. In this case we have to provide a temporary data structure,
  88. // i.e. for the duration of the call, for the thread to link itself on the
  89. // list of waiting threads. _internal_omni_thread_dummy provides such
  90. // a data structure and _internal_omni_thread_helper is a helper class to
  91. // deal with this special case for wait() and timedwait(). Once created,
  92. // the _internal_omni_thread_dummy is cached for use by the next wait() or
  93. // timedwait() call from a non-omni_thread. This is probably worth doing
  94. // because creating a Semaphore is quite heavy weight.
  95. class _internal_omni_thread_helper;
  96. class _internal_omni_thread_dummy : public omni_thread {
  97. public:
  98.   inline _internal_omni_thread_dummy() : next(0) { }
  99.   inline ~_internal_omni_thread_dummy() { }
  100.   friend class _internal_omni_thread_helper;
  101. private:
  102.   _internal_omni_thread_dummy* next;
  103. };
  104. class _internal_omni_thread_helper {
  105. public:
  106.   inline _internal_omni_thread_helper()  { 
  107.     d = 0;
  108.     t = omni_thread::self();
  109.     if (!t) {
  110.       omni_mutex_lock sync(cachelock);
  111.       if (cache) {
  112. d = cache;
  113. cache = cache->next;
  114.       }
  115.       else {
  116. d = new _internal_omni_thread_dummy;
  117.       }
  118.       t = d;
  119.     }
  120.   }
  121.   inline ~_internal_omni_thread_helper() { 
  122.     if (d) {
  123.       omni_mutex_lock sync(cachelock);
  124.       d->next = cache;
  125.       cache = d;
  126.     }
  127.   }
  128.   inline operator omni_thread* () { return t; }
  129.   inline omni_thread* operator->() { return t; }
  130.   static _internal_omni_thread_dummy* cache;
  131.   static omni_mutex                   cachelock;
  132. private:
  133.   _internal_omni_thread_dummy* d;
  134.   omni_thread*                 t;
  135. };
  136. _internal_omni_thread_dummy* _internal_omni_thread_helper::cache = 0;
  137. omni_mutex                   _internal_omni_thread_helper::cachelock;
  138. omni_condition::omni_condition(omni_mutex* m) : mutex(m)
  139. {
  140.     InitializeCriticalSection(&crit);
  141.     waiting_head = waiting_tail = NULL;
  142. }
  143. omni_condition::~omni_condition(void)
  144. {
  145.     DeleteCriticalSection(&crit);
  146.     DB( if (waiting_head != NULL) {
  147. cerr << "omni_condition::~omni_condition: list of waiting threads "
  148.      << "is not emptyn";
  149.     } )
  150. }
  151. void
  152. omni_condition::wait(void)
  153. {
  154.     _internal_omni_thread_helper me;
  155.     EnterCriticalSection(&crit);
  156.     me->cond_next = NULL;
  157.     me->cond_prev = waiting_tail;
  158.     if (waiting_head == NULL)
  159. waiting_head = me;
  160.     else
  161. waiting_tail->cond_next = me;
  162.     waiting_tail = me;
  163.     me->cond_waiting = TRUE;
  164.     LeaveCriticalSection(&crit);
  165.     mutex->unlock();
  166.     DWORD result = WaitForSingleObject(me->cond_semaphore, INFINITE);
  167.     mutex->lock();
  168.     if (result != WAIT_OBJECT_0)
  169. throw omni_thread_fatal(GetLastError());
  170. }
  171. int
  172. omni_condition::timedwait(unsigned long abs_sec, unsigned long abs_nsec)
  173. {
  174.     _internal_omni_thread_helper me;
  175.     EnterCriticalSection(&crit);
  176.     me->cond_next = NULL;
  177.     me->cond_prev = waiting_tail;
  178.     if (waiting_head == NULL)
  179. waiting_head = me;
  180.     else
  181. waiting_tail->cond_next = me;
  182.     waiting_tail = me;
  183.     me->cond_waiting = TRUE;
  184.     LeaveCriticalSection(&crit);
  185.     mutex->unlock();
  186.     unsigned long now_sec, now_nsec;
  187.     get_time_now(&now_sec, &now_nsec);
  188.     DWORD timeout = (abs_sec-now_sec) * 1000 + (abs_nsec-now_nsec) / 1000000;
  189.     if ((abs_sec <= now_sec) && ((abs_sec < now_sec) || (abs_nsec < abs_nsec)))
  190. timeout = 0;
  191.     DWORD result = WaitForSingleObject(me->cond_semaphore, timeout);
  192.     if (result == WAIT_TIMEOUT) {
  193. EnterCriticalSection(&crit);
  194. if (me->cond_waiting) {
  195.     if (me->cond_prev != NULL)
  196. me->cond_prev->cond_next = me->cond_next;
  197.     else
  198. waiting_head = me->cond_next;
  199.     if (me->cond_next != NULL)
  200. me->cond_next->cond_prev = me->cond_prev;
  201.     else
  202. waiting_tail = me->cond_prev;
  203.     me->cond_waiting = FALSE;
  204.     LeaveCriticalSection(&crit);
  205.     mutex->lock();
  206.     return 0;
  207. }
  208. //
  209. // We timed out but another thread still signalled us.  Wait for
  210. // the semaphore (it _must_ have been signalled) to decrement it
  211. // again.  Return that we were signalled, not that we timed out.
  212. //
  213. LeaveCriticalSection(&crit);
  214. result = WaitForSingleObject(me->cond_semaphore, INFINITE);
  215.     }
  216.     if (result != WAIT_OBJECT_0)
  217. throw omni_thread_fatal(GetLastError());
  218.     mutex->lock();
  219.     return 1;
  220. }
  221. void
  222. omni_condition::signal(void)
  223. {
  224.     EnterCriticalSection(&crit);
  225.     if (waiting_head != NULL) {
  226. omni_thread* t = waiting_head;
  227. waiting_head = t->cond_next;
  228. if (waiting_head == NULL)
  229.     waiting_tail = NULL;
  230. else
  231.     waiting_head->cond_prev = NULL;
  232. t->cond_waiting = FALSE;
  233. if (!ReleaseSemaphore(t->cond_semaphore, 1, NULL)) {
  234.     int rc = GetLastError();
  235.     LeaveCriticalSection(&crit);
  236.     throw omni_thread_fatal(rc);
  237. }
  238.     }
  239.     LeaveCriticalSection(&crit);
  240. }
  241. void
  242. omni_condition::broadcast(void)
  243. {
  244.     EnterCriticalSection(&crit);
  245.     while (waiting_head != NULL) {
  246. omni_thread* t = waiting_head;
  247. waiting_head = t->cond_next;
  248. if (waiting_head == NULL)
  249.     waiting_tail = NULL;
  250. else
  251.     waiting_head->cond_prev = NULL;
  252. t->cond_waiting = FALSE;
  253. if (!ReleaseSemaphore(t->cond_semaphore, 1, NULL)) {
  254.     int rc = GetLastError();
  255.     LeaveCriticalSection(&crit);
  256.     throw omni_thread_fatal(rc);
  257. }
  258.     }
  259.     LeaveCriticalSection(&crit);
  260. }
  261. ///////////////////////////////////////////////////////////////////////////
  262. //
  263. // Counting semaphore
  264. //
  265. ///////////////////////////////////////////////////////////////////////////
  266. #define SEMAPHORE_MAX 0x7fffffff
  267. omni_semaphore::omni_semaphore(unsigned int initial)
  268. {
  269.     nt_sem = CreateSemaphore(NULL, initial, SEMAPHORE_MAX, NULL);
  270.     if (nt_sem == NULL) {
  271.       DB( cerr << "omni_semaphore::omni_semaphore: CreateSemaphore error "
  272.      << GetLastError() << endl );
  273.       throw omni_thread_fatal(GetLastError());
  274.     }
  275. }
  276. omni_semaphore::~omni_semaphore(void)
  277. {
  278.   if (!CloseHandle(nt_sem)) {
  279.     DB( cerr << "omni_semaphore::~omni_semaphore: CloseHandle error "
  280.      << GetLastError() << endl );
  281.     throw omni_thread_fatal(GetLastError());
  282.   }
  283. }
  284. void
  285. omni_semaphore::wait(void)
  286. {
  287.     if (WaitForSingleObject(nt_sem, INFINITE) != WAIT_OBJECT_0)
  288. throw omni_thread_fatal(GetLastError());
  289. }
  290. int
  291. omni_semaphore::trywait(void)
  292. {
  293.     switch (WaitForSingleObject(nt_sem, 0)) {
  294.     case WAIT_OBJECT_0:
  295. return 1;
  296.     case WAIT_TIMEOUT:
  297. return 0;
  298.     }
  299.     throw omni_thread_fatal(GetLastError());
  300.     return 0; /* keep msvc++ happy */
  301. }
  302. void
  303. omni_semaphore::post(void)
  304. {
  305.     if (!ReleaseSemaphore(nt_sem, 1, NULL))
  306. throw omni_thread_fatal(GetLastError());
  307. }
  308. ///////////////////////////////////////////////////////////////////////////
  309. //
  310. // Thread
  311. //
  312. ///////////////////////////////////////////////////////////////////////////
  313. //
  314. // Static variables
  315. //
  316. int omni_thread::init_t::count = 0;
  317. omni_mutex* omni_thread::next_id_mutex;
  318. int omni_thread::next_id = 0;
  319. static DWORD self_tls_index;
  320. //
  321. // Initialisation function (gets called before any user code).
  322. //
  323. omni_thread::init_t::init_t(void)
  324. {
  325.     if (count++ != 0) // only do it once however many objects get created.
  326. return;
  327.     DB(cerr << "omni_thread::init: NT implementation initialisingn");
  328.     self_tls_index = TlsAlloc();
  329.     if (self_tls_index == 0xffffffff)
  330. throw omni_thread_fatal(GetLastError());
  331.     next_id_mutex = new omni_mutex;
  332.     //
  333.     // Create object for this (i.e. initial) thread.
  334.     //
  335.     omni_thread* t = new omni_thread;
  336.     t->_state = STATE_RUNNING;
  337.     if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
  338.  GetCurrentProcess(), &t->handle,
  339.  0, FALSE, DUPLICATE_SAME_ACCESS))
  340. throw omni_thread_fatal(GetLastError());
  341.     t->nt_id = GetCurrentThreadId();
  342.     DB(cerr << "initial thread " << t->id() << " NT thread id " << t->nt_id
  343.        << endl);
  344.     if (!TlsSetValue(self_tls_index, (LPVOID)t))
  345. throw omni_thread_fatal(GetLastError());
  346.     if (!SetThreadPriority(t->handle, nt_priority(PRIORITY_NORMAL)))
  347. throw omni_thread_fatal(GetLastError());
  348. }
  349. //
  350. // Wrapper for thread creation.
  351. //
  352. extern "C" 
  353. #ifndef __BCPLUSPLUS__
  354. unsigned __stdcall
  355. #else
  356. void _USERENTRY
  357. #endif
  358. omni_thread_wrapper(void* ptr)
  359. {
  360.     omni_thread* me = (omni_thread*)ptr;
  361.     DB(cerr << "omni_thread_wrapper: thread " << me->id()
  362.        << " startedn");
  363.     if (!TlsSetValue(self_tls_index, (LPVOID)me))
  364. throw omni_thread_fatal(GetLastError());
  365.     //
  366.     // Now invoke the thread function with the given argument.
  367.     //
  368.     if (me->fn_void != NULL) {
  369. (*me->fn_void)(me->thread_arg);
  370. omni_thread::exit();
  371.     }
  372.     if (me->fn_ret != NULL) {
  373. void* return_value = (*me->fn_ret)(me->thread_arg);
  374. omni_thread::exit(return_value);
  375.     }
  376.     if (me->detached) {
  377. me->run(me->thread_arg);
  378. omni_thread::exit();
  379.     } else {
  380. void* return_value = me->run_undetached(me->thread_arg);
  381. omni_thread::exit(return_value);
  382.     }
  383.     // should never get here.
  384. #ifndef __BCPLUSPLUS__
  385.     return 0;
  386. #endif
  387. }
  388. //
  389. // Constructors for omni_thread - set up the thread object but don't
  390. // start it running.
  391. //
  392. // construct a detached thread running a given function.
  393. omni_thread::omni_thread(void (*fn)(void*), void* arg, priority_t pri)
  394. {
  395.     common_constructor(arg, pri, 1);
  396.     fn_void = fn;
  397.     fn_ret = NULL;
  398. }
  399. // construct an undetached thread running a given function.
  400. omni_thread::omni_thread(void* (*fn)(void*), void* arg, priority_t pri)
  401. {
  402.     common_constructor(arg, pri, 0);
  403.     fn_void = NULL;
  404.     fn_ret = fn;
  405. }
  406. // construct a thread which will run either run() or run_undetached().
  407. omni_thread::omni_thread(void* arg, priority_t pri)
  408. {
  409.     common_constructor(arg, pri, 1);
  410.     fn_void = NULL;
  411.     fn_ret = NULL;
  412. }
  413. // common part of all constructors.
  414. void
  415. omni_thread::common_constructor(void* arg, priority_t pri, int det)
  416. {
  417.     _state = STATE_NEW;
  418.     _priority = pri;
  419.     next_id_mutex->lock();
  420.     _id = next_id++;
  421.     next_id_mutex->unlock();
  422.     thread_arg = arg;
  423.     detached = det; // may be altered in start_undetached()
  424.     cond_semaphore = CreateSemaphore(NULL, 0, SEMAPHORE_MAX, NULL);
  425.     if (cond_semaphore == NULL)
  426. throw omni_thread_fatal(GetLastError());
  427.     cond_next = cond_prev = NULL;
  428.     cond_waiting = FALSE;
  429.     handle = NULL;
  430. }
  431. //
  432. // Destructor for omni_thread.
  433. //
  434. omni_thread::~omni_thread(void)
  435. {
  436.     DB(cerr << "destructor called for thread " << id() << endl);
  437.     if (!CloseHandle(handle))
  438. throw omni_thread_fatal(GetLastError());
  439.     if (!CloseHandle(cond_semaphore))
  440. throw omni_thread_fatal(GetLastError());
  441. }
  442. //
  443. // Start the thread
  444. //
  445. void
  446. omni_thread::start(void)
  447. {
  448.     omni_mutex_lock l(mutex);
  449.     if (_state != STATE_NEW)
  450. throw omni_thread_invalid();
  451. #ifndef __BCPLUSPLUS__
  452.     // MSVC++ or compatiable
  453.     unsigned int t;
  454.     handle = (HANDLE)_beginthreadex(
  455.                         NULL,
  456. 0,
  457. omni_thread_wrapper,
  458. (LPVOID)this,
  459. CREATE_SUSPENDED, 
  460. &t);
  461.     nt_id = t;
  462.     if (handle == NULL)
  463.       throw omni_thread_fatal(GetLastError());
  464. #else
  465.     // Borland C++
  466.     handle = (HANDLE)_beginthreadNT(omni_thread_wrapper,
  467.     0,
  468.     (void*)this,
  469.     NULL,
  470.     CREATE_SUSPENDED,
  471.     &nt_id);
  472.     if (handle == INVALID_HANDLE_VALUE)
  473.       throw omni_thread_fatal(errno);
  474. #endif
  475.     if (!SetThreadPriority(handle, _priority))
  476.       throw omni_thread_fatal(GetLastError());
  477.     if (ResumeThread(handle) == 0xffffffff)
  478. throw omni_thread_fatal(GetLastError());
  479.     _state = STATE_RUNNING;
  480. }
  481. //
  482. // Start a thread which will run the member function run_undetached().
  483. //
  484. void
  485. omni_thread::start_undetached(void)
  486. {
  487.     if ((fn_void != NULL) || (fn_ret != NULL))
  488. throw omni_thread_invalid();
  489.     detached = 0;
  490.     start();
  491. }
  492. //
  493. // join - simply check error conditions & call WaitForSingleObject.
  494. //
  495. void
  496. omni_thread::join(void** status)
  497. {
  498.     mutex.lock();
  499.     if ((_state != STATE_RUNNING) && (_state != STATE_TERMINATED)) {
  500. mutex.unlock();
  501. throw omni_thread_invalid();
  502.     }
  503.     mutex.unlock();
  504.     if (this == self())
  505. throw omni_thread_invalid();
  506.     if (detached)
  507. throw omni_thread_invalid();
  508.     DB(cerr << "omni_thread::join: doing WaitForSingleObjectn");
  509.     if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0)
  510. throw omni_thread_fatal(GetLastError());
  511.     DB(cerr << "omni_thread::join: WaitForSingleObject succeededn");
  512.     if (status)
  513.       *status = return_val;
  514.     delete this;
  515. }
  516. //
  517. // Change this thread's priority.
  518. //
  519. void
  520. omni_thread::set_priority(priority_t pri)
  521. {
  522.     omni_mutex_lock l(mutex);
  523.     if (_state != STATE_RUNNING)
  524. throw omni_thread_invalid();
  525.     _priority = pri;
  526.     if (!SetThreadPriority(handle, nt_priority(pri)))
  527. throw omni_thread_fatal(GetLastError());
  528. }
  529. //
  530. // create - construct a new thread object and start it running.  Returns thread
  531. // object if successful, null pointer if not.
  532. //
  533. // detached version
  534. omni_thread*
  535. omni_thread::create(void (*fn)(void*), void* arg, priority_t pri)
  536. {
  537.     omni_thread* t = new omni_thread(fn, arg, pri);
  538.     t->start();
  539.     return t;
  540. }
  541. // undetached version
  542. omni_thread*
  543. omni_thread::create(void* (*fn)(void*), void* arg, priority_t pri)
  544. {
  545.     omni_thread* t = new omni_thread(fn, arg, pri);
  546.     t->start();
  547.     return t;
  548. }
  549. //
  550. // exit() _must_ lock the mutex even in the case of a detached thread.  This is
  551. // because a thread may run to completion before the thread that created it has
  552. // had a chance to get out of start().  By locking the mutex we ensure that the
  553. // creating thread must have reached the end of start() before we delete the
  554. // thread object.  Of course, once the call to start() returns, the user can
  555. // still incorrectly refer to the thread object, but that's their problem.
  556. //
  557. void
  558. omni_thread::exit(void* return_value)
  559. {
  560.     omni_thread* me = self();
  561.     if (me)
  562.       {
  563. me->mutex.lock();
  564. me->_state = STATE_TERMINATED;
  565. me->mutex.unlock();
  566. DB(cerr << "omni_thread::exit: thread " << me->id() << " detached "
  567.    << me->detached << " return value " << return_value << endl);
  568. if (me->detached) {
  569.   delete me;
  570. } else {
  571.   me->return_val = return_value;
  572. }
  573.       }
  574.     else
  575.       {
  576. DB(cerr << "omni_thread::exit: called with a non-omnithread. Exit quietly." << endl);
  577.       }
  578. #ifndef __BCPLUSPLUS__
  579.     // MSVC++ or compatiable
  580.     //   _endthreadex() does not automatically closes the thread handle.
  581.     //   The omni_thread dtor closes the thread handle.
  582.     _endthreadex(0);
  583. #else
  584.     // Borland C++
  585.     //   _endthread() does not automatically closes the thread handle.
  586.     //   _endthreadex() is only available if __MFC_COMPAT__ is defined and
  587.     //   all it does is to call _endthread().
  588.     _endthread();
  589. #endif
  590. }
  591. omni_thread*
  592. omni_thread::self(void)
  593. {
  594.     LPVOID me;
  595.     me = TlsGetValue(self_tls_index);
  596.     if (me == NULL) {
  597.       DB(cerr << "omni_thread::self: called with a non-ominthread. NULL is returned." << endl);
  598.     }
  599.     return (omni_thread*)me;
  600. }
  601. void
  602. omni_thread::yield(void)
  603. {
  604.     Sleep(0);
  605. }
  606. #define MAX_SLEEP_SECONDS (DWORD)4294966 // (2**32-2)/1000
  607. void
  608. omni_thread::sleep(unsigned long secs, unsigned long nanosecs)
  609. {
  610.     if (secs <= MAX_SLEEP_SECONDS) {
  611. Sleep(secs * 1000 + nanosecs / 1000000);
  612. return;
  613.     }
  614.     DWORD no_of_max_sleeps = secs / MAX_SLEEP_SECONDS;
  615.     for (DWORD i = 0; i < no_of_max_sleeps; i++)
  616. Sleep(MAX_SLEEP_SECONDS * 1000);
  617.     Sleep((secs % MAX_SLEEP_SECONDS) * 1000 + nanosecs / 1000000);
  618. }
  619. void
  620. omni_thread::get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
  621.       unsigned long rel_sec, unsigned long rel_nsec)
  622. {
  623.     get_time_now(abs_sec, abs_nsec);
  624.     *abs_nsec += rel_nsec;
  625.     *abs_sec += rel_sec + *abs_nsec / 1000000000;
  626.     *abs_nsec = *abs_nsec % 1000000000;
  627. }
  628. int
  629. omni_thread::nt_priority(priority_t pri)
  630. {
  631.     switch (pri) {
  632.     case PRIORITY_LOW:
  633. return THREAD_PRIORITY_LOWEST;
  634.     case PRIORITY_NORMAL:
  635. return THREAD_PRIORITY_NORMAL;
  636.     case PRIORITY_HIGH:
  637. return THREAD_PRIORITY_HIGHEST;
  638.     }
  639.     throw omni_thread_invalid();
  640.     return 0; /* keep msvc++ happy */
  641. }
  642. static void
  643. get_time_now(unsigned long* abs_sec, unsigned long* abs_nsec)
  644. {
  645.     static int days_in_preceding_months[12]
  646. = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
  647.     static int days_in_preceding_months_leap[12]
  648. = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
  649.     SYSTEMTIME st;
  650.     GetSystemTime(&st);
  651.     *abs_nsec = st.wMilliseconds * 1000000;
  652.     // this formula should work until 1st March 2100
  653.     DWORD days = ((st.wYear - 1970) * 365 + (st.wYear - 1969) / 4
  654.   + ((st.wYear % 4)
  655.      ? days_in_preceding_months[st.wMonth - 1]
  656.      : days_in_preceding_months_leap[st.wMonth - 1])
  657.   + st.wDay - 1);
  658.     *abs_sec = st.wSecond + 60 * (st.wMinute + 60 * (st.wHour + 24 * days));
  659. }