2002-11-11 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mono / io-layer / threads.c
1 /*
2  * threads.c:  Thread handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #if HAVE_BOEHM_GC
12 #include <mono/os/gc_wrapper.h>
13 #include "mono/utils/mono-hash.h"
14 #endif
15 #include <glib.h>
16 #include <string.h>
17 #include <pthread.h>
18 #include <sched.h>
19 #include <sys/time.h>
20 #include <errno.h>
21
22 #include <mono/io-layer/wapi.h>
23 #include <mono/io-layer/wapi-private.h>
24 #include <mono/io-layer/timed-thread.h>
25 #include <mono/io-layer/handles-private.h>
26 #include <mono/io-layer/misc-private.h>
27 #include <mono/io-layer/mono-mutex.h>
28 #include <mono/io-layer/thread-private.h>
29 #include <mono/io-layer/mono-spinlock.h>
30
31 #undef DEBUG
32 #undef TLS_DEBUG
33 #undef TLS_PTHREAD_MUTEX
34
35
36 /* Hash threads with tids. I thought of using TLS for this, but that
37  * would have to set the data in the new thread, which is more hassle
38  */
39 static mono_once_t thread_hash_once = MONO_ONCE_INIT;
40 static mono_mutex_t thread_hash_mutex = MONO_MUTEX_INITIALIZER;
41 static GHashTable *thread_hash=NULL;
42
43 #if HAVE_BOEHM_GC
44 static MonoGHashTable *tls_gc_hash = NULL;
45 #endif
46
47 static void thread_close_private (gpointer handle);
48 static void thread_own (gpointer handle);
49
50 struct _WapiHandleOps _wapi_thread_ops = {
51         NULL,                           /* close_shared */
52         thread_close_private,           /* close_private */
53         NULL,                           /* signal */
54         thread_own,                     /* own */
55         NULL,                           /* is_owned */
56 };
57
58 static mono_once_t thread_ops_once=MONO_ONCE_INIT;
59
60 static void thread_ops_init (void)
61 {
62         _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
63                                             WAPI_HANDLE_CAP_WAIT);
64 }
65
66 static void thread_close_private (gpointer handle)
67 {
68         struct _WapiHandlePrivate_thread *thread_handle;
69         gboolean ok;
70         
71         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, NULL,
72                                 (gpointer *)&thread_handle);
73         if(ok==FALSE) {
74                 g_warning (G_GNUC_PRETTY_FUNCTION
75                            ": error looking up thread handle %p", handle);
76                 return;
77         }
78         
79 #ifdef DEBUG
80         g_message(G_GNUC_PRETTY_FUNCTION
81                   ": closing thread handle %p with thread %p id %ld",
82                   handle, thread_handle->thread,
83                   thread_handle->thread->id);
84 #endif
85
86         if(thread_handle->thread!=NULL) {
87                 _wapi_timed_thread_destroy (thread_handle->thread);
88         }
89 }
90
91 static void thread_own (gpointer handle)
92 {
93         struct _WapiHandle_thread *thread_handle;
94         struct _WapiHandlePrivate_thread *thread_private_handle;
95         gboolean ok;
96         
97         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
98                                 (gpointer *)&thread_handle,
99                                 (gpointer *)&thread_private_handle);
100         if(ok==FALSE) {
101                 g_warning (G_GNUC_PRETTY_FUNCTION
102                            ": error looking up thread handle %p", handle);
103                 return;
104         }
105
106         if(thread_private_handle->joined==FALSE) {
107                 _wapi_timed_thread_join (thread_private_handle->thread, NULL,
108                                          NULL);
109                 thread_private_handle->joined=TRUE;
110         }
111 }
112
113 static void thread_exit(guint32 exitstatus, gpointer handle)
114 {
115         struct _WapiHandle_thread *thread_handle;
116         struct _WapiHandlePrivate_thread *thread_private_handle;
117         gboolean ok;
118         
119         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
120                                 (gpointer *)&thread_handle,
121                                 (gpointer *)&thread_private_handle);
122         if(ok==FALSE) {
123                 g_warning (G_GNUC_PRETTY_FUNCTION
124                            ": error looking up thread handle %p", handle);
125                 return;
126         }
127
128         _wapi_handle_lock_handle (handle);
129
130 #ifdef DEBUG
131         g_message (G_GNUC_PRETTY_FUNCTION
132                    ": Recording thread handle %p exit status", handle);
133 #endif
134         
135         thread_handle->exitstatus=exitstatus;
136         thread_handle->state=THREAD_STATE_EXITED;
137         _wapi_handle_set_signal_state (handle, TRUE, TRUE);
138
139         _wapi_handle_unlock_handle (handle);
140         
141 #ifdef DEBUG
142         g_message(G_GNUC_PRETTY_FUNCTION
143                   ": Recording thread handle %p id %ld status as %d",
144                   handle, thread_private_handle->thread->id, exitstatus);
145 #endif
146
147         /* Remove this thread from the hash */
148         mono_mutex_lock(&thread_hash_mutex);
149         g_hash_table_remove(thread_hash, &thread_private_handle->thread->id);
150         mono_mutex_unlock(&thread_hash_mutex);
151
152         /* The thread is no longer active, so unref it */
153         _wapi_handle_unref (handle);
154 }
155
156 static void thread_hash_init(void)
157 {
158         thread_hash=g_hash_table_new(g_int_hash, g_int_equal);
159 }
160
161 /**
162  * CreateThread:
163  * @security: Ignored for now.
164  * @stacksize: the size in bytes of the new thread's stack. Use 0 to
165  * default to the normal stack size. (Ignored for now).
166  * @start: The function that the new thread should start with
167  * @param: The parameter to give to @start.
168  * @create: If 0, the new thread is ready to run immediately.  If
169  * %CREATE_SUSPENDED, the new thread will be in the suspended state,
170  * requiring a ResumeThread() call to continue running.
171  * @tid: If non-NULL, the ID of the new thread is stored here.
172  *
173  * Creates a new threading handle.
174  *
175  * Return value: a new handle, or NULL
176  */
177 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize G_GNUC_UNUSED,
178                       WapiThreadStart start, gpointer param, guint32 create,
179                       guint32 *tid) 
180 {
181         struct _WapiHandle_thread *thread_handle;
182         struct _WapiHandlePrivate_thread *thread_private_handle;
183         gpointer handle;
184         gboolean ok;
185         int ret;
186         
187         mono_once(&thread_hash_once, thread_hash_init);
188         mono_once (&thread_ops_once, thread_ops_init);
189         
190         if(start==NULL) {
191                 return(NULL);
192         }
193         
194         handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
195         if(handle==_WAPI_HANDLE_INVALID) {
196                 g_warning (G_GNUC_PRETTY_FUNCTION
197                            ": error creating thread handle");
198                 return(NULL);
199         }
200
201         _wapi_handle_lock_handle (handle);
202         
203         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
204                                 (gpointer *)&thread_handle,
205                                 (gpointer *)&thread_private_handle);
206         if(ok==FALSE) {
207                 g_warning (G_GNUC_PRETTY_FUNCTION
208                            ": error looking up thread handle %p", handle);
209                 _wapi_handle_unlock_handle (handle);
210                 return(NULL);
211         }
212
213         /* Hold a reference while the thread is active, because we use
214          * the handle to store thread exit information
215          */
216         _wapi_handle_ref (handle);
217
218         thread_handle->state=THREAD_STATE_START;
219         
220         /* Lock around the thread create, so that the new thread cant
221          * race us to look up the thread handle in GetCurrentThread()
222          */
223         mono_mutex_lock(&thread_hash_mutex);
224         
225         ret=_wapi_timed_thread_create(&thread_private_handle->thread, NULL,
226                                       create, start, thread_exit, param,
227                                       handle);
228         if(ret!=0) {
229 #ifdef DEBUG
230                 g_message(G_GNUC_PRETTY_FUNCTION ": Thread create error: %s",
231                           strerror(ret));
232 #endif
233                 mono_mutex_unlock(&thread_hash_mutex);
234                 _wapi_handle_unlock_handle (handle);
235                 _wapi_handle_unref (handle);
236                 
237                 /* And again, because of the reference we took above */
238                 _wapi_handle_unref (handle);
239                 return(NULL);
240         }
241
242         g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
243                             handle);
244         mono_mutex_unlock(&thread_hash_mutex);
245         
246 #ifdef DEBUG
247         g_message(G_GNUC_PRETTY_FUNCTION
248                   ": Started thread handle %p thread %p ID %ld", handle,
249                   thread_private_handle->thread,
250                   thread_private_handle->thread->id);
251 #endif
252         
253         if(tid!=NULL) {
254 #ifdef PTHREAD_POINTER_ID
255                 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
256 #else
257                 *tid=thread_private_handle->thread->id;
258 #endif
259         }
260
261         _wapi_handle_unlock_handle (handle);
262         
263         return(handle);
264 }
265
266 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 tid)
267 {
268         gpointer ret=NULL;
269         
270 #ifdef DEBUG
271         g_message (G_GNUC_PRETTY_FUNCTION ": looking up thread %d", tid);
272 #endif
273
274         mono_mutex_lock(&thread_hash_mutex);
275         
276         ret=g_hash_table_lookup(thread_hash, &tid);
277         mono_mutex_unlock(&thread_hash_mutex);
278         
279         if(ret!=NULL) {
280                 _wapi_handle_ref (ret);
281         }
282         
283 #ifdef DEBUG
284         g_message (G_GNUC_PRETTY_FUNCTION ": returning thread handle %p", ret);
285 #endif
286         
287         return(ret);
288 }
289
290 /**
291  * ExitThread:
292  * @exitcode: Sets the thread's exit code, which can be read from
293  * another thread with GetExitCodeThread().
294  *
295  * Terminates the calling thread.  A thread can also exit by returning
296  * from its start function. When the last thread in a process
297  * terminates, the process itself terminates.
298  */
299 void ExitThread(guint32 exitcode)
300 {
301         /* No thread created yet.  */
302         if (thread_hash == NULL)
303                 exit(exitcode);
304
305         _wapi_timed_thread_exit(exitcode);
306 }
307
308 /**
309  * GetExitCodeThread:
310  * @handle: The thread handle to query
311  * @exitcode: The thread @handle exit code is stored here
312  *
313  * Finds the exit code of @handle, and stores it in @exitcode.  If the
314  * thread @handle is still running, the value stored is %STILL_ACTIVE.
315  *
316  * Return value: %TRUE, or %FALSE on error.
317  */
318 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
319 {
320         struct _WapiHandle_thread *thread_handle;
321         struct _WapiHandlePrivate_thread *thread_private_handle;
322         gboolean ok;
323         
324         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
325                                 (gpointer *)&thread_handle,
326                                 (gpointer *)&thread_private_handle);
327         if(ok==FALSE) {
328                 g_warning (G_GNUC_PRETTY_FUNCTION
329                            ": error looking up thread handle %p", handle);
330                 return(FALSE);
331         }
332         
333 #ifdef DEBUG
334         g_message(G_GNUC_PRETTY_FUNCTION
335                   ": Finding exit status for thread handle %p id %ld", handle,
336                   thread_private_handle->thread->id);
337 #endif
338
339         if(exitcode==NULL) {
340 #ifdef DEBUG
341                 g_message(G_GNUC_PRETTY_FUNCTION
342                           ": Nowhere to store exit code");
343 #endif
344                 return(FALSE);
345         }
346         
347         if(thread_handle->state!=THREAD_STATE_EXITED) {
348 #ifdef DEBUG
349                 g_message(G_GNUC_PRETTY_FUNCTION
350                           ": Thread still active (state %d, exited is %d)",
351                           thread_handle->state, THREAD_STATE_EXITED);
352 #endif
353                 *exitcode=STILL_ACTIVE;
354                 return(TRUE);
355         }
356         
357         *exitcode=thread_handle->exitstatus;
358         
359         return(TRUE);
360 }
361
362 /**
363  * GetCurrentThreadId:
364  *
365  * Looks up the thread ID of the current thread.  This ID can be
366  * passed to OpenThread() to create a new handle on this thread.
367  *
368  * Return value: the thread ID.
369  */
370 guint32 GetCurrentThreadId(void)
371 {
372         pthread_t tid=pthread_self();
373         
374 #ifdef PTHREAD_POINTER_ID
375         return(GPOINTER_TO_UINT(tid));
376 #else
377         return(tid);
378 #endif
379 }
380
381 /**
382  * GetCurrentThread:
383  *
384  * Looks up the handle associated with the current thread.  Under
385  * Windows this is a pseudohandle, and must be duplicated with
386  * DuplicateHandle() for some operations.
387  *
388  * Return value: The current thread handle, or %NULL on failure.
389  * (Unknown whether Windows has a possible failure here.  It may be
390  * necessary to implement the pseudohandle-constant behaviour).
391  */
392 gpointer GetCurrentThread(void)
393 {
394         gpointer ret=NULL;
395         guint32 tid;
396         
397         tid=GetCurrentThreadId();
398         
399         mono_mutex_lock(&thread_hash_mutex);
400
401         ret=g_hash_table_lookup(thread_hash, &tid);
402         
403         mono_mutex_unlock(&thread_hash_mutex);
404         
405         return(ret);
406 }
407
408 /**
409  * ResumeThread:
410  * @handle: the thread handle to resume
411  *
412  * Decrements the suspend count of thread @handle. A thread can only
413  * run if its suspend count is zero.
414  *
415  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
416  */
417 guint32 ResumeThread(gpointer handle)
418 {
419         struct _WapiHandle_thread *thread_handle;
420         struct _WapiHandlePrivate_thread *thread_private_handle;
421         gboolean ok;
422         
423         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
424                                 (gpointer *)&thread_handle,
425                                 (gpointer *)&thread_private_handle);
426         if(ok==FALSE) {
427                 g_warning (G_GNUC_PRETTY_FUNCTION
428                            ": error looking up thread handle %p", handle);
429                 return(0xFFFFFFFF);
430         }
431
432         /* This is still a kludge that only copes with starting a
433          * thread that was suspended on create, so don't bother with
434          * the suspend count crap yet
435          */
436         _wapi_timed_thread_resume (thread_private_handle->thread);
437         
438         return(0xFFFFFFFF);
439 }
440
441 /**
442  * SuspendThread:
443  * @handle: the thread handle to suspend
444  *
445  * Increments the suspend count of thread @handle. A thread can only
446  * run if its suspend count is zero.
447  *
448  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
449  */
450 guint32 SuspendThread(gpointer handle G_GNUC_UNUSED)
451 {
452         return(0xFFFFFFFF);
453 }
454
455 /*
456  * We assume here that TLS_MINIMUM_AVAILABLE is less than
457  * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
458  * library usage.
459  *
460  * Currently TLS_MINIMUM_AVAILABLE is 64 and _POSIX_THREAD_KEYS_MAX
461  * (the minimum value for PTHREAD_KEYS_MAX) is 128, so we should be
462  * fine.
463  */
464
465 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
466 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
467 #ifdef TLS_PTHREAD_MUTEX
468 static mono_mutex_t TLS_mutex=MONO_MUTEX_INITIALIZER;
469 #else
470 static guint32 TLS_spinlock=0;
471 #endif
472
473 /**
474  * TlsAlloc:
475  *
476  * Allocates a Thread Local Storage (TLS) index.  Any thread in the
477  * same process can use this index to store and retrieve values that
478  * are local to that thread.
479  *
480  * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
481  * is available.
482  */
483 guint32 TlsAlloc(void)
484 {
485         guint32 i;
486         
487 #ifdef TLS_PTHREAD_MUTEX
488         mono_mutex_lock(&TLS_mutex);
489 #else
490         MONO_SPIN_LOCK (TLS_spinlock);
491 #endif
492         
493         for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
494                 if(TLS_used[i]==FALSE) {
495                         TLS_used[i]=TRUE;
496                         pthread_key_create(&TLS_keys[i], NULL);
497
498 #ifdef TLS_PTHREAD_MUTEX
499                         mono_mutex_unlock(&TLS_mutex);
500 #else
501                         MONO_SPIN_UNLOCK (TLS_spinlock);
502 #endif
503         
504 #ifdef TLS_DEBUG
505                         g_message (G_GNUC_PRETTY_FUNCTION ": returning key %d",
506                                    i);
507 #endif
508                         
509                         return(i);
510                 }
511         }
512
513 #ifdef TLS_PTHREAD_MUTEX
514         mono_mutex_unlock(&TLS_mutex);
515 #else
516         MONO_SPIN_UNLOCK (TLS_spinlock);
517 #endif
518         
519 #ifdef TLS_DEBUG
520         g_message (G_GNUC_PRETTY_FUNCTION ": out of indices");
521 #endif
522                         
523         
524         return(TLS_OUT_OF_INDEXES);
525 }
526
527 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
528
529 /**
530  * TlsFree:
531  * @idx: The TLS index to free
532  *
533  * Releases a TLS index, making it available for reuse.  This call
534  * will delete any TLS data stored under index @idx in all threads.
535  *
536  * Return value: %TRUE on success, %FALSE otherwise.
537  */
538 gboolean TlsFree(guint32 idx)
539 {
540 #ifdef TLS_DEBUG
541         g_message (G_GNUC_PRETTY_FUNCTION ": freeing key %d", idx);
542 #endif
543
544 #ifdef TLS_PTHREAD_MUTEX
545         mono_mutex_lock(&TLS_mutex);
546 #else
547         MONO_SPIN_LOCK (TLS_spinlock);
548 #endif
549         
550         if(TLS_used[idx]==FALSE) {
551 #ifdef TLS_PTHREAD_MUTEX
552                 mono_mutex_unlock(&TLS_mutex);
553 #else
554                 MONO_SPIN_UNLOCK (TLS_spinlock);
555 #endif
556                 return(FALSE);
557         }
558         
559         TLS_used[idx]=FALSE;
560         pthread_key_delete(TLS_keys[idx]);
561         
562 #if HAVE_BOEHM_GC
563         mono_g_hash_table_remove (tls_gc_hash, MAKE_GC_ID (idx));
564 #endif
565
566 #ifdef TLS_PTHREAD_MUTEX
567         mono_mutex_unlock(&TLS_mutex);
568 #else
569         MONO_SPIN_UNLOCK (TLS_spinlock);
570 #endif
571         
572         return(TRUE);
573 }
574
575 /**
576  * TlsGetValue:
577  * @idx: The TLS index to retrieve
578  *
579  * Retrieves the TLS data stored under index @idx.
580  *
581  * Return value: The value stored in the TLS index @idx in the current
582  * thread, or %NULL on error.  As %NULL can be a valid return value,
583  * in this case GetLastError() returns %ERROR_SUCCESS.
584  */
585 gpointer TlsGetValue(guint32 idx)
586 {
587         gpointer ret;
588         
589 #ifdef TLS_DEBUG
590         g_message (G_GNUC_PRETTY_FUNCTION ": looking up key %d", idx);
591 #endif
592
593 #ifdef TLS_PTHREAD_MUTEX
594         mono_mutex_lock(&TLS_mutex);
595 #else
596         MONO_SPIN_LOCK (TLS_spinlock);
597 #endif
598         
599         if(TLS_used[idx]==FALSE) {
600 #ifdef TLS_DEBUG
601                 g_message (G_GNUC_PRETTY_FUNCTION ": key %d unused", idx);
602 #endif
603
604 #ifdef TLS_PTHREAD_MUTEX
605                 mono_mutex_unlock(&TLS_mutex);
606 #else
607                 MONO_SPIN_UNLOCK (TLS_spinlock);
608 #endif
609                 return(NULL);
610         }
611         
612         ret=pthread_getspecific(TLS_keys[idx]);
613
614 #ifdef TLS_DEBUG
615         g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", ret);
616 #endif
617         
618 #ifdef TLS_PTHREAD_MUTEX
619         mono_mutex_unlock(&TLS_mutex);
620 #else
621         MONO_SPIN_UNLOCK (TLS_spinlock);
622 #endif
623         
624         return(ret);
625 }
626
627 /**
628  * TlsSetValue:
629  * @idx: The TLS index to store
630  * @value: The value to store under index @idx
631  *
632  * Stores @value at TLS index @idx.
633  *
634  * Return value: %TRUE on success, %FALSE otherwise.
635  */
636 gboolean TlsSetValue(guint32 idx, gpointer value)
637 {
638         int ret;
639
640 #ifdef TLS_DEBUG
641         g_message (G_GNUC_PRETTY_FUNCTION ": setting key %d to %p", idx,
642                    value);
643 #endif
644         
645 #ifdef TLS_PTHREAD_MUTEX
646         mono_mutex_lock(&TLS_mutex);
647 #else
648         MONO_SPIN_LOCK (TLS_spinlock);
649 #endif
650         
651         if(TLS_used[idx]==FALSE) {
652 #ifdef TLS_DEBUG
653                 g_message (G_GNUC_PRETTY_FUNCTION ": key %d unused", idx);
654 #endif
655
656 #ifdef TLS_PTHREAD_MUTEX
657                 mono_mutex_unlock(&TLS_mutex);
658 #else
659                 MONO_SPIN_UNLOCK (TLS_spinlock);
660 #endif
661                 return(FALSE);
662         }
663         
664         ret=pthread_setspecific(TLS_keys[idx], value);
665         if(ret!=0) {
666 #ifdef TLS_DEBUG
667                 g_message (G_GNUC_PRETTY_FUNCTION
668                            ": pthread_setspecific error: %s", strerror (ret));
669 #endif
670
671 #ifdef TLS_PTHREAD_MUTEX
672                 mono_mutex_unlock(&TLS_mutex);
673 #else
674                 MONO_SPIN_UNLOCK (TLS_spinlock);
675 #endif
676                 return(FALSE);
677         }
678         
679 #if HAVE_BOEHM_GC
680         if (!tls_gc_hash)
681                 tls_gc_hash = mono_g_hash_table_new(g_direct_hash, g_direct_equal);
682         mono_g_hash_table_insert (tls_gc_hash, MAKE_GC_ID (idx), value);
683 #endif
684
685 #ifdef TLS_PTHREAD_MUTEX
686         mono_mutex_unlock(&TLS_mutex);
687 #else
688         MONO_SPIN_UNLOCK (TLS_spinlock);
689 #endif
690         
691         return(TRUE);
692 }
693
694 /**
695  * Sleep:
696  * @ms: The time in milliseconds to suspend for
697  *
698  * Suspends execution of the current thread for @ms milliseconds.  A
699  * value of zero causes the thread to relinquish its time slice.  A
700  * value of %INFINITE causes an infinite delay.
701  */
702 void Sleep(guint32 ms)
703 {
704         struct timespec req, rem;
705         div_t divvy;
706         int ret;
707         
708 #ifdef DEBUG
709         g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
710 #endif
711
712         if(ms==0) {
713                 sched_yield();
714                 return;
715         }
716         
717         /* FIXME: check for INFINITE and sleep forever */
718         divvy=div((int)ms, 1000);
719         
720         req.tv_sec=divvy.quot;
721         req.tv_nsec=divvy.rem*1000000;
722         
723 again:
724         ret=nanosleep(&req, &rem);
725         if(ret==-1) {
726                 /* Sleep interrupted with rem time remaining */
727 #ifdef DEBUG
728                 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
729                 
730                 g_message(G_GNUC_PRETTY_FUNCTION ": Still got %d ms to go",
731                           rems);
732 #endif
733                 req=rem;
734                 goto again;
735         }
736 }
737
738 /* FIXME: implement alertable */
739 void SleepEx(guint32 ms, gboolean alertable)
740 {
741         if(alertable==TRUE) {
742                 g_warning(G_GNUC_PRETTY_FUNCTION ": alertable not implemented");
743         }
744         
745         Sleep(ms);
746 }