w32: Use cast by uintptr_t for thread ID.
[npth.git] / w32 / npth.c
1 /* npth.c - a lightweight implementation of pth over native threads
2  * Copyright (C) 2011, 2014 g10 Code GmbH
3  *
4  * This file is part of nPth.
5  *
6  * nPth is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * nPth is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14  * the GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20 /* We implement the join mechanism ourself.  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <io.h>
29
30 #include "npth.h"
31
32 #include <stdio.h>
33 #define DEBUG_CALLS 1
34 #define _npth_debug(x, ...) fprintf(stderr, __VA_ARGS__)
35
36 #ifndef TEST
37 #undef  DEBUG_CALLS
38 #define DEBUG_CALLS 0
39 #undef _npth_debug
40 #define _npth_debug(x, ...)
41 #endif
42
43 /* This seems to be a common standard.  */
44 #define THREAD_NAME_MAX 15
45
46 /* The global lock that excludes all threads but one.  Note that this
47    implements the single-user-thread policy, but also protects all our
48    global data such as the thread_table.  GOT_SCEPTRE is a flag used
49    for debugging to tell wether we hold SCEPTRE.  */
50 static CRITICAL_SECTION sceptre;
51 static int got_sceptre;
52
53
54 /* This flag is set as soon as npth_init has been called or if any
55  * thread has been created.  It will never be cleared again.  The only
56  * purpose is to make npth_protect and npth_unprotect more robust in
57  * that they can be shortcut when npth_init has not yet been called.
58  * This is important for libraries which want to support nPth by using
59  * those two functions but may have been initialized before nPth. */
60 static int initialized_or_any_threads;
61
62
63 typedef struct npth_impl_s *npth_impl_t;
64 #define MAX_THREADS 1024
65 #define INVALID_THREAD_ID 0
66 /* Thread ID to thread context table.  We never allocate ID 0.  */
67 static npth_impl_t thread_table[MAX_THREADS];
68
69 /* The TLS index to store thread ID of the current thread.  Used to
70    make faster lookups of the thread data.  */
71 DWORD tls_index;
72
73
74 \f
75 /* Map a windows error value (GetLastError) to a POSIX error value.  */
76 static int
77 map_error (int winerr)
78 {
79   /* FIXME */
80   return EIO;
81 }
82
83
84 static int
85 wait_for_single_object (HANDLE obj, DWORD msecs)
86 {
87   DWORD res;
88
89   res = WaitForSingleObject(obj, msecs);
90
91   if (res == WAIT_ABANDONED)
92     return EDEADLK;
93   else if (res == WAIT_TIMEOUT)
94     return ETIMEDOUT;
95   else if (res == WAIT_FAILED)
96     return map_error (GetLastError());
97   else if (res != WAIT_OBJECT_0)
98     return EINTR;
99   else
100     return 0;
101 }
102
103 \f
104 int
105 npth_clock_gettime(struct timespec *tp)
106 {
107   FILETIME ftime;
108   ULARGE_INTEGER systime;
109   unsigned long long usecs;
110
111   GetSystemTimeAsFileTime (&ftime);
112   systime.LowPart = ftime.dwLowDateTime;
113   systime.HighPart = ftime.dwHighDateTime;
114
115   /* systime.QuadPart has the 100-nanosecond intervals since Jan 1, 1601.  */
116   tp->tv_sec = systime.QuadPart / 10000000ULL;
117   tp->tv_nsec = (systime.QuadPart * 100ULL) % 1000000000ULL;
118   return 0;
119 }
120
121
122 static int
123 calculate_timeout (const struct timespec *abstime, DWORD *msecs_r)
124 {
125   struct timespec tp;
126   struct timespec tp_delta;
127   DWORD msecs;
128
129   npth_clock_gettime (&tp);
130   /* Make sure there is a positive time delta.  */
131   if (!(npth_timercmp (&tp, abstime, <)))
132     return ETIMEDOUT;
133
134   npth_timersub (abstime, &tp, &tp_delta);
135   /* Make sure to round up to at least one millisecond.  Note that
136      within reasonable timeouts and the above macros, we should always
137      end up with a positive wait time here.  */
138   msecs = (tp_delta.tv_sec * 1000) + (tp_delta.tv_nsec + 999999) / 1000000;
139   if (msecs < 1)
140     {
141       /* Log a critical error here.  */
142       return ETIMEDOUT;
143     }
144
145   *msecs_r = msecs;
146   return 0;
147 }
148
149 \f
150 static void
151 enter_npth (const char *function)
152 {
153   int res;
154
155   if (DEBUG_CALLS)
156     _npth_debug (DEBUG_CALLS, "tid %lu: enter_npth (%s)\n",
157                  npth_self (), function ? function : "unknown");
158   got_sceptre = 0;
159   LeaveCriticalSection (&sceptre);
160 }
161
162
163 static void
164 leave_npth (const char *function)
165 {
166   EnterCriticalSection (&sceptre);
167   got_sceptre = 1;
168
169   if (DEBUG_CALLS)
170     _npth_debug (DEBUG_CALLS, "tid %lu: leave_npth (%s)\n",
171                  npth_self (), function ? function : "");
172 }
173
174 #define ENTER() enter_npth(__FUNCTION__)
175 #define LEAVE() leave_npth(__FUNCTION__)
176
177 \f
178 struct npth_impl_s
179 {
180   /* Usually there is one ref owned by the thread as long as it is
181      running, and one ref for everybody else as long as the thread is
182      joinable.  */
183   int refs;
184
185   HANDLE handle;
186
187   /* True if thread is detached.  */
188   int detached;
189
190   /* The start routine and arg.  */
191   void *(*start_routine) (void *);
192   void *start_arg;
193
194   char name[THREAD_NAME_MAX + 1];
195
196   /* Doubly-linked list for the waiter queue in condition
197      variables.  */
198   npth_impl_t next;
199   npth_impl_t *prev_ptr;
200
201   /* The event on which this thread waits when it is queued.  */
202   HANDLE event;
203
204   void *result;
205 };
206
207
208 static void
209 dequeue_thread (npth_impl_t thread)
210 {
211   /* Unlink the thread from any condition waiter queue.  */
212   if (thread->next)
213     {
214       thread->next->prev_ptr = thread->prev_ptr;
215       thread->next = NULL;
216     }
217   if (thread->prev_ptr)
218     {
219       *(thread->prev_ptr) = thread->next;
220       thread->prev_ptr = NULL;
221     }
222 }
223
224
225 /* Enqueue THREAD to come after the thread whose next pointer is
226    prev_ptr.  */
227 static void
228 enqueue_thread (npth_impl_t thread, npth_impl_t *prev_ptr)
229 {
230   if (*prev_ptr)
231     (*prev_ptr)->prev_ptr = &thread->next;
232   thread->prev_ptr = prev_ptr;
233   thread->next = *prev_ptr;
234   *prev_ptr = thread;
235 }
236
237
238 static int
239 find_thread (npth_t thread_id, npth_impl_t *thread)
240 {
241   if (thread_id < 1 || thread_id >= MAX_THREADS)
242     return ESRCH;
243
244   if (! thread_table[thread_id])
245     return ESRCH;
246
247   *thread = thread_table[thread_id];
248   return 0;
249 }
250
251
252 static int
253 new_thread (npth_t *thread_id)
254 {
255   npth_impl_t thread;
256   int id;
257
258   /* ID 0 is never allocated.  */
259   for (id = 1; id < MAX_THREADS; id++)
260     if (! thread_table[id])
261       break;
262   if (id == MAX_THREADS)
263     return EAGAIN;
264
265   thread = malloc (sizeof (*thread));
266   if (! thread)
267     return errno;
268
269   thread->refs = 1;
270   thread->handle = INVALID_HANDLE_VALUE;
271   thread->detached = 0;
272   thread->start_routine = NULL;
273   thread->start_arg = NULL;
274   thread->next = NULL;
275   thread->prev_ptr = NULL;
276   /* We create the event when it is first needed (not all threads wait
277      on conditions).  */
278   thread->event = INVALID_HANDLE_VALUE;
279   memset (thread->name, '\0', sizeof (thread->name));
280
281   thread_table[id] = thread;
282
283   *thread_id = id;
284   return 0;
285 }
286
287
288 static void
289 free_thread (npth_t thread_id)
290 {
291   npth_impl_t thread = thread_table[thread_id];
292
293   if (thread->handle)
294     CloseHandle (thread->handle);
295
296   /* Unlink the thread from any condition waiter queue.  */
297   dequeue_thread (thread);
298
299   free (thread);
300
301   thread_table[thread_id] = NULL;
302 }
303
304
305 static void
306 deref_thread (npth_t thread_id)
307 {
308   npth_impl_t thread = thread_table[thread_id];
309
310   thread->refs -= 1;
311   if (thread->refs == 0)
312     free_thread (thread_id);
313 }
314
315
316 \f
317 int
318 npth_init (void)
319 {
320   int err;
321   npth_t thread_id;
322   BOOL res;
323   HANDLE handle;
324   npth_impl_t thread;
325
326   InitializeCriticalSection (&sceptre);
327
328   /* Track that we have been initialized.  */
329   initialized_or_any_threads = 1;
330
331   /* Fake a thread table item for the main thread.  */
332   tls_index = TlsAlloc();
333   if (tls_index == TLS_OUT_OF_INDEXES)
334     return map_error (GetLastError());
335
336   err = new_thread(&thread_id);
337   if (err)
338     return err;
339
340   /* GetCurrentThread() is not usable by other threads, so it needs to
341      be duplicated.  */
342   res = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
343                         GetCurrentProcess(), &handle,
344                         0, FALSE, DUPLICATE_SAME_ACCESS);
345   if (!res)
346     {
347       free_thread (thread_id);
348       return map_error(GetLastError());
349     }
350
351   thread = thread_table[thread_id];
352   thread->handle = handle;
353
354   if (! TlsSetValue(tls_index, (LPVOID)(uintptr_t) thread_id))
355     return map_error (GetLastError());
356
357   LEAVE();
358   return 0;
359 }
360
361 \f
362 struct npth_attr_s
363 {
364   int detachstate;
365 };
366
367
368 int
369 npth_attr_init (npth_attr_t *attr_r)
370 {
371   npth_attr_t attr;
372
373   attr = malloc (sizeof *attr);
374   if (!attr)
375     return errno;
376
377   attr->detachstate = NPTH_CREATE_JOINABLE;
378   *attr_r = attr;
379   return 0;
380 }
381
382
383 int
384 npth_attr_destroy (npth_attr_t *attr)
385 {
386   free (*attr);
387   *attr = NULL;
388   return 0;
389 }
390
391
392 int
393 npth_attr_getdetachstate (npth_attr_t *attr,
394                           int *detachstate)
395 {
396   *detachstate = (*attr)->detachstate;
397   return 0;
398 }
399
400
401 int
402 npth_attr_setdetachstate (npth_attr_t *attr, int detachstate)
403 {
404   if (detachstate != NPTH_CREATE_JOINABLE
405       && detachstate != NPTH_CREATE_DETACHED)
406     return EINVAL;
407
408   (*attr)->detachstate = detachstate;
409   return 0;
410 }
411
412
413 int
414 npth_getname_np (npth_t target_thread, char *buf, size_t buflen)
415 {
416   npth_impl_t thread;
417   int err;
418
419   if (buflen < THREAD_NAME_MAX + 1)
420     return ERANGE;
421
422   err = find_thread (target_thread, &thread);
423   if (err)
424     return err;
425
426   strcpy (buf, thread->name);
427   return 0;
428 }
429
430
431 int
432 npth_setname_np (npth_t target_thread, const char *name)
433 {
434   npth_impl_t thread;
435   int err;
436
437   if (strlen(name) > THREAD_NAME_MAX)
438     return ERANGE;
439
440   err = find_thread (target_thread, &thread);
441   if (err)
442     return err;
443
444   strcpy (thread->name, name);
445   return 0;
446 }
447
448
449 static DWORD
450 thread_start (void *arg)
451 {
452   npth_t thread_id = (npth_t)(uintptr_t) arg;
453   npth_impl_t thread;
454   void *result;
455
456   if (! TlsSetValue(tls_index, (LPVOID)(uintptr_t) thread_id))
457     /* FIXME: There is not much we can do here.  */
458     ;
459
460   LEAVE();
461   /* We must be protected here, because we access the global
462      thread_table.  */
463
464   thread = thread_table[thread_id];
465   result = thread->start_routine (thread->start_arg);
466   /* We might not return here if the thread calls npth_exit().  */
467
468   thread->result = result;
469
470   /* Any joiner will be signaled once we terminate.  */
471   deref_thread (thread_id);
472
473   ENTER();
474
475   /* We can not return result, as that is a void*, not a DWORD.  */
476   return 0;
477 }
478
479
480 int
481 npth_create (npth_t *newthread, const npth_attr_t *user_attr,
482              void *(*start_routine) (void *), void *start_arg)
483 {
484   int err = 0;
485   npth_t thread_id = INVALID_THREAD_ID;
486   npth_attr_t attr;
487   int attr_allocated;
488   npth_impl_t thread;
489   HANDLE handle;
490
491   /* We must stay protected here, because we access the global
492      thread_table.  Also, creating a new thread is not a blocking
493      operation.  */
494   if (user_attr)
495     {
496       attr = *user_attr;
497       attr_allocated = 0;
498     }
499   else
500     {
501       err = npth_attr_init (&attr);
502       if (err)
503         return err;
504       attr_allocated = 1;
505     }
506
507   err = new_thread (&thread_id);
508   if (err)
509     goto err_out;
510
511   thread = thread_table[thread_id];
512   if (attr->detachstate == NPTH_CREATE_DETACHED)
513     thread->detached = 1;
514   else
515     thread->refs += 1;
516
517   thread->start_routine = start_routine;
518   thread->start_arg = start_arg;
519
520   handle = CreateThread (NULL, 0,
521                          (LPTHREAD_START_ROUTINE)thread_start,
522                          (void *)(uintptr_t) thread_id, CREATE_SUSPENDED,
523                          NULL);
524   if (handle == NULL)
525     {
526       err = map_error (GetLastError());
527       goto err_out;
528     }
529
530   thread->handle = handle;
531   *newthread = thread_id;
532
533   ResumeThread (thread->handle);
534
535   if (attr_allocated)
536     npth_attr_destroy (&attr);
537
538   return 0;
539
540  err_out:
541   if (thread_id)
542     free_thread (thread_id);
543   if (attr_allocated)
544     npth_attr_destroy (&attr);
545
546   return err;
547 }
548
549
550 npth_t
551 npth_self (void)
552 {
553   LPVOID thread_id;
554
555   thread_id = TlsGetValue (tls_index);
556   if (thread_id == 0 && GetLastError() != ERROR_SUCCESS)
557     /* FIXME: Log the error.  */
558     ;
559   return (npth_t)(uintptr_t) thread_id;
560 }
561
562
563 /* Not part of the public interface at the moment, thus static.  */
564 static int
565 npth_tryjoin_np (npth_t thread_id, void **thread_return)
566 {
567   int err;
568   npth_impl_t thread;
569   int res;
570
571   err = find_thread (thread_id, &thread);
572   if (err)
573     return err;
574
575   if (thread->detached)
576     return EINVAL;
577
578   /* No need to allow competing threads to enter when we can get the
579      lock immediately.  */
580   err = wait_for_single_object (thread->handle, 0);
581   if (err == ETIMEDOUT)
582     err = EBUSY;
583
584   if (err)
585     return err;
586
587   if (thread_return)
588     *thread_return = thread->result;
589   deref_thread (thread_id);
590
591   return 0;
592 }
593
594
595 int
596 npth_join (npth_t thread_id, void **thread_return)
597 {
598   int err;
599   npth_impl_t thread;
600   int res;
601
602   /* No need to allow competing threads to enter when we can get the
603      lock immediately.  */
604   err = npth_tryjoin_np (thread_id, thread_return);
605   if (err != EBUSY)
606     return err;
607
608   err = find_thread (thread_id, &thread);
609   if (err)
610     return err;
611
612   if (thread->detached)
613     return EINVAL;
614
615   ENTER();
616   err = wait_for_single_object (thread->handle, INFINITE);
617   LEAVE();
618
619   if (err)
620     return err;
621
622   if (thread_return)
623     *thread_return = thread->result;
624   deref_thread (thread_id);
625
626   return 0;
627 }
628
629
630 int
631 npth_detach (npth_t thread_id)
632 {
633   int err;
634   npth_impl_t thread;
635
636   err = find_thread (thread_id, &thread);
637   if (err)
638     return err;
639
640   if (thread->detached)
641     return EINVAL;
642
643   /* The detached flag indicates to other thread that the outside
644      reference in the global thread table has been consumed.  */
645   thread->detached = 1;
646   deref_thread (thread_id);
647
648   return 0;
649 }
650
651
652 void
653 npth_exit (void *retval)
654 {
655   int err;
656   npth_t thread_id;
657   npth_impl_t thread;
658
659   thread_id = npth_self();
660   err = find_thread (thread_id, &thread);
661   if (err)
662     /* FIXME: log this?  */
663     return;
664
665   thread->result = retval;
666   /* Any joiner will be signaled once we terminate.  */
667   deref_thread (thread_id);
668
669   ENTER();
670
671   /* We can not use retval here, as that is a void*, not a DWORD.  */
672   ExitThread(0);
673
674   /* Never reached.  But just in case ExitThread does return... */
675   LEAVE();
676 }
677
678
679 \f
680 int
681 npth_key_create (npth_key_t *key,
682                  void (*destr_function) (void *))
683 {
684   DWORD idx;
685
686   if (destr_function)
687     return EOPNOTSUPP;
688
689   idx = TlsAlloc ();
690   if (idx == TLS_OUT_OF_INDEXES)
691     return map_error (GetLastError());
692
693   *key = idx;
694   return 0;
695 }
696
697
698 int
699 npth_key_delete (npth_key_t key)
700 {
701   BOOL res;
702
703   res = TlsFree (key);
704   if (res == 0)
705     return map_error (GetLastError());
706   return 0;
707 }
708
709
710 void *
711 npth_getspecific (npth_key_t key)
712 {
713   /* Pthread doesn't support error reporting beyond returning NULL for
714      an invalid key, which is also what TlsGetValue returns in that
715      case.  */
716   return TlsGetValue (key);
717 }
718
719
720 int
721 npth_setspecific (npth_key_t key, const void *pointer)
722 {
723   BOOL res;
724
725   res = TlsSetValue (key, (void *) pointer);
726   if (res == 0)
727     return map_error (GetLastError());
728
729   return 0;
730 }
731
732 \f
733 struct npth_mutexattr_s
734 {
735   int kind;
736 };
737
738
739 int
740 npth_mutexattr_init (npth_mutexattr_t *attr_r)
741 {
742   npth_mutexattr_t attr;
743
744   attr = malloc (sizeof *attr);
745   if (!attr)
746     return errno;
747
748   attr->kind = NPTH_MUTEX_DEFAULT;
749   *attr_r = attr;
750   return 0;
751 }
752
753
754 int
755 npth_mutexattr_destroy (npth_mutexattr_t *attr)
756 {
757   free (*attr);
758   *attr = NULL;
759   return 0;
760 }
761
762
763 int
764 npth_mutexattr_gettype (const npth_mutexattr_t *attr,
765                         int *kind)
766 {
767   *kind = (*attr)->kind;
768   return 0;
769 }
770
771
772 int
773 npth_mutexattr_settype (npth_mutexattr_t *attr, int kind)
774 {
775   if (kind != NPTH_MUTEX_NORMAL && kind != NPTH_MUTEX_RECURSIVE
776       && kind != NPTH_MUTEX_ERRORCHECK)
777     return EINVAL;
778
779   (*attr)->kind = kind;
780   return 0;
781 }
782
783 \f
784 struct npth_mutex_s
785 {
786   /* We have to use a mutex, not a CRITICAL_SECTION, because the
787      latter can not be used with timed waits.  */
788   HANDLE mutex;
789 };
790
791
792 int
793 npth_mutex_init (npth_mutex_t *mutex_r, const npth_mutexattr_t *mutex_attr)
794 {
795   npth_mutex_t mutex;
796
797   /* We can not check *mutex_r here, as it may contain random data.  */
798   mutex = malloc (sizeof (*mutex));
799   if (!mutex)
800     return errno;
801
802   /* We ignore MUTEX_ATTR.  */
803   mutex->mutex = CreateMutex (NULL, FALSE, NULL);
804   if (!mutex->mutex)
805     {
806       int err = map_error (GetLastError());
807       free (mutex);
808       return err;
809     }
810
811   *mutex_r = mutex;
812   return 0;
813 }
814
815
816 int
817 npth_mutex_destroy (npth_mutex_t *mutex)
818 {
819   BOOL res;
820
821   if (*mutex == 0 || *mutex == NPTH_MUTEX_INITIALIZER
822       || *mutex == NPTH_RECURSIVE_MUTEX_INITIALIZER_NP)
823     return EINVAL;
824
825   res = CloseHandle ((*mutex)->mutex);
826   if (res == 0)
827     return map_error (GetLastError());
828
829   free (*mutex);
830   *mutex = NULL;
831
832   return 0;
833 }
834
835
836 /* Must be called with global lock held.  */
837 static int
838 mutex_init_check (npth_mutex_t *mutex)
839 {
840   int err;
841   npth_mutexattr_t attr;
842   int kind;
843
844   if (*mutex == 0)
845     return EINVAL;
846
847   if ((*mutex) == NPTH_MUTEX_INITIALIZER)
848     kind = NPTH_MUTEX_NORMAL;
849   else if ((*mutex) == NPTH_RECURSIVE_MUTEX_INITIALIZER_NP)
850     kind = NPTH_MUTEX_RECURSIVE;
851   else if ((*mutex) == NPTH_ERRORCHECK_MUTEX_INITIALIZER_NP)
852     kind = NPTH_MUTEX_ERRORCHECK;
853   else
854     /* Already initialized.  */
855     return 0;
856
857   /* Make sure we don't try again in case of error.  */
858   *mutex = 0;
859
860   err = npth_mutexattr_init (&attr);
861   if (err)
862     return err;
863
864   err = npth_mutexattr_settype (&attr, kind);
865   if (err)
866     {
867       npth_mutexattr_destroy (&attr);
868       return err;
869     }
870
871   err = npth_mutex_init (mutex, &attr);
872   npth_mutexattr_destroy (&attr);
873
874   return err;
875 }
876
877
878 int
879 npth_mutex_lock (npth_mutex_t *mutex)
880 {
881   int err;
882
883   /* While we are protected, let's check for a static initializer.  */
884   err = mutex_init_check (mutex);
885   if (err)
886     return err;
887
888   /* No need to allow competing threads to enter when we can get the
889      lock immediately.  */
890   err = npth_mutex_trylock (mutex);
891   if (err != EBUSY)
892     return err;
893
894   ENTER();
895   err = wait_for_single_object ((*mutex)->mutex, INFINITE);
896   LEAVE();
897
898   if (err)
899     return err;
900
901   return 0;
902 }
903
904
905 int
906 npth_mutex_trylock (npth_mutex_t *mutex)
907 {
908   int err;
909   DWORD res;
910
911   /* While we are protected, let's check for a static initializer.  */
912   err = mutex_init_check (mutex);
913   if (err)
914     return err;
915
916   /* We do not leave the global lock for a quick try.  */
917   err = wait_for_single_object ((*mutex)->mutex, 0);
918   if (err == ETIMEDOUT)
919     err = EBUSY;
920
921   if (err)
922     return err;
923
924   return 0;
925 }
926
927
928 int
929 npth_mutex_timedlock (npth_mutex_t *mutex, const struct timespec *abstime)
930 {
931   int err;
932   DWORD msecs;
933
934   /* While we are protected, let's check for a static initializer.  */
935   err = mutex_init_check (mutex);
936   if (err)
937     return err;
938
939   /* No need to allow competing threads to enter when we can get the
940      lock immediately.  */
941   err = npth_mutex_trylock (mutex);
942   if (err != EBUSY)
943     return err;
944
945   err = calculate_timeout (abstime, &msecs);
946   if (err)
947     return err;
948
949   ENTER();
950   err = wait_for_single_object ((*mutex)->mutex, msecs);
951   LEAVE();
952
953   if (err)
954     return err;
955
956   return 0;
957 }
958
959
960 int
961 npth_mutex_unlock (npth_mutex_t *mutex)
962 {
963   BOOL res;
964
965   if (*mutex == 0 || *mutex == NPTH_MUTEX_INITIALIZER
966       || *mutex == NPTH_RECURSIVE_MUTEX_INITIALIZER_NP)
967     return EINVAL;
968
969   res = ReleaseMutex ((*mutex)->mutex);
970   if (res == 0)
971     return map_error (GetLastError());
972
973   return 0;
974 }
975
976 \f
977 struct npth_cond_s
978 {
979   /* All conditions are protected by the global lock, so this is
980      simple.  */
981
982   /* The waiter queue.  */
983   npth_impl_t waiter;
984 };
985
986
987 int
988 npth_cond_init (npth_cond_t *cond_r,
989                 const npth_condattr_t *cond_attr)
990 {
991   npth_cond_t cond;
992
993   if (cond_attr != NULL)
994     return EINVAL;
995
996   /* We can not check *cond_r here, as it may contain random data.  */
997   cond = malloc (sizeof (*cond));
998   if (!cond)
999     return errno;
1000
1001   cond->waiter = NULL;
1002
1003   *cond_r = cond;
1004   return 0;
1005 }
1006
1007
1008 int
1009 npth_cond_destroy (npth_cond_t *cond)
1010 {
1011   if (*cond == 0)
1012     return EINVAL;
1013
1014   if ((*cond)->waiter)
1015     return EBUSY;
1016
1017   free (*cond);
1018   *cond = NULL;
1019
1020   return 0;
1021 }
1022
1023
1024 /* Must be called with global lock held.  */
1025 static int
1026 cond_init_check (npth_cond_t *cond)
1027 {
1028   int err;
1029
1030   if (*cond == 0 || *cond == NPTH_COND_INITIALIZER)
1031     return EINVAL;
1032
1033   if (*cond != NPTH_COND_INITIALIZER)
1034     /* Already initialized.  */
1035     return 0;
1036
1037   /* Make sure we don't try again in case of error.  */
1038   *cond = 0;
1039
1040   err = npth_cond_init (cond, NULL);
1041
1042   return err;
1043 }
1044
1045
1046 int
1047 npth_cond_signal (npth_cond_t *cond)
1048 {
1049   int err;
1050   npth_impl_t thread;
1051   DWORD res;
1052
1053   /* While we are protected, let's check for a static initializer.  */
1054   err = cond_init_check (cond);
1055   if (err)
1056     return err;
1057
1058   if ((*cond)->waiter == INVALID_THREAD_ID)
1059     return 0;
1060
1061   /* Dequeue the first thread and wake it up.  */
1062   thread = (*cond)->waiter;
1063   dequeue_thread (thread);
1064
1065   res = SetEvent (thread->event);
1066   if (res == 0)
1067     /* FIXME: An error here implies a mistake in the npth code.  Log it.  */
1068     ;
1069
1070   /* Force the woken up thread into the mutex lock function (for the
1071      mutex associated with the condition, which is why we have to
1072      release the global lock here).  This helps to ensure fairness,
1073      because otherwise our own thread might release and reacquire the
1074      lock first (followed by removing the condition that lead to the
1075      wakeup) and starve the woken up thread.  */
1076   ENTER ();
1077   Sleep (0);
1078   LEAVE ();
1079
1080   return 0;
1081 }
1082
1083
1084 int
1085 npth_cond_broadcast (npth_cond_t *cond)
1086 {
1087   int err;
1088   npth_impl_t thread;
1089   DWORD res;
1090   int any;
1091
1092   /* While we are protected, let's check for a static initializer.  */
1093   err = cond_init_check (cond);
1094   if (err)
1095     return err;
1096
1097   if ((*cond)->waiter == INVALID_THREAD_ID)
1098     return 0;
1099
1100   while ((*cond)->waiter)
1101     {
1102       /* Dequeue the first thread and wake it up.  */
1103       thread = (*cond)->waiter;
1104       dequeue_thread (thread);
1105
1106       res = SetEvent (thread->event);
1107       if (res == 0)
1108         /* FIXME: An error here implies a mistake in the npth code.  Log it.  */
1109         ;
1110     }
1111
1112   /* Force the woken up threads into the mutex lock function (for the
1113      mutex associated with the condition, which is why we have to
1114      release the global lock here).  This helps to ensure fairness,
1115      because otherwise our own thread might release and reacquire the
1116      lock first (followed by removing the condition that lead to the
1117      wakeup) and starve the woken up threads.  */
1118   ENTER ();
1119   Sleep (0);
1120   LEAVE ();
1121
1122   return 0;
1123 }
1124
1125
1126 /* As a special exception in W32 NPTH, mutex can be NULL, in which
1127    case the global lock doubles as the mutex protecting the condition.
1128    This is used internally in the RW implementation as an
1129    optimization.  Note that this is safe as long as the caller does
1130    not yield to other threads (directly or indirectly) between
1131    checking the condition and waiting on it.  */
1132 int
1133 npth_cond_wait (npth_cond_t *cond, npth_mutex_t *mutex)
1134 {
1135   int err;
1136   int err2;
1137   BOOL bres;
1138   npth_impl_t thread;
1139   npth_impl_t *prev_ptr;
1140
1141   /* While we are protected, let's check for a static initializer.  */
1142   err = cond_init_check (cond);
1143   if (err)
1144     return err;
1145
1146   err = find_thread (npth_self(), &thread);
1147   if (err)
1148     return err;
1149
1150   /* Ensure there is an event.  */
1151   if (thread->event == INVALID_HANDLE_VALUE)
1152     {
1153       thread->event = CreateEvent (NULL, TRUE, FALSE, NULL);
1154       if (thread->event == INVALID_HANDLE_VALUE)
1155         return map_error (GetLastError());
1156     }
1157
1158   /* Find end of queue and enqueue the thread.  */
1159   prev_ptr = &(*cond)->waiter;
1160   while (*prev_ptr)
1161     prev_ptr = &(*prev_ptr)->next;
1162   enqueue_thread (thread, prev_ptr);
1163
1164   /* Make sure the event is not signaled before releasing the mutex.  */
1165   bres = ResetEvent (thread->event);
1166   if (bres == 0)
1167     /* Log an error.  */
1168     ;
1169
1170   if (mutex)
1171     {
1172       err = npth_mutex_unlock (mutex);
1173       if (err)
1174         {
1175           dequeue_thread (thread);
1176           return err;
1177         }
1178     }
1179
1180   ENTER();
1181   err = wait_for_single_object (thread->event, INFINITE);
1182   LEAVE();
1183
1184   /* Make sure the thread is dequeued (in case of error).  */
1185   dequeue_thread (thread);
1186
1187   if (mutex)
1188     {
1189       err2 = npth_mutex_lock (mutex);
1190       if (err2)
1191         /* FIXME: Log this at least.  */
1192         ;
1193     }
1194
1195   if (err)
1196     return err;
1197
1198   return 0;
1199 }
1200
1201
1202 int
1203 npth_cond_timedwait (npth_cond_t *cond, npth_mutex_t *mutex,
1204                      const struct timespec *abstime)
1205 {
1206   int err;
1207   int err2;
1208   BOOL bres;
1209   npth_impl_t thread;
1210   npth_impl_t *prev_ptr;
1211   DWORD msecs;
1212
1213   err = calculate_timeout (abstime, &msecs);
1214   if (err)
1215     {
1216       if (err != ETIMEDOUT)
1217         return err;
1218
1219       /* We have to give up the lock anyway to give others a chance to
1220          signal or broadcast.  */
1221       err = npth_mutex_unlock (mutex);
1222       if (err)
1223         return err;
1224       ENTER();
1225       Sleep (0);
1226       LEAVE();
1227       err = npth_mutex_lock (mutex);
1228       if (err)
1229         return (err);
1230       return ETIMEDOUT;
1231     }
1232
1233   /* While we are protected, let's check for a static initializer.  */
1234   err = cond_init_check (cond);
1235   if (err)
1236     return err;
1237
1238   err = find_thread (npth_self(), &thread);
1239   if (err)
1240     return err;
1241
1242   /* Ensure there is an event.  */
1243   if (thread->event == INVALID_HANDLE_VALUE)
1244     {
1245       thread->event = CreateEvent (NULL, TRUE, FALSE, NULL);
1246       if (thread->event == INVALID_HANDLE_VALUE)
1247         return map_error (GetLastError());
1248     }
1249
1250   /* Make sure the event is not signaled.  */
1251   bres = ResetEvent (thread->event);
1252   if (bres == 0)
1253     /* Log an error.  */
1254     ;
1255
1256   /* Find end of queue and enqueue the thread.  */
1257   prev_ptr = &(*cond)->waiter;
1258   while (*prev_ptr)
1259     prev_ptr = &(*prev_ptr)->next;
1260   enqueue_thread (thread, prev_ptr);
1261
1262   err = npth_mutex_unlock (mutex);
1263   if (err)
1264     {
1265       dequeue_thread (thread);
1266       return err;
1267     }
1268
1269   ENTER();
1270   err = wait_for_single_object (thread->event, msecs);
1271   LEAVE();
1272
1273   err2 = npth_mutex_lock (mutex);
1274   if (err2)
1275     /* FIXME: Log this at least.  */
1276     ;
1277
1278   if (err)
1279     return err;
1280
1281   return 0;
1282 }
1283
1284 \f
1285 struct npth_rwlockattr_s
1286 {
1287   int kind;
1288 };
1289
1290
1291 int
1292 npth_rwlockattr_init (npth_rwlockattr_t *attr_r)
1293 {
1294   npth_rwlockattr_t attr;
1295
1296   attr = malloc (sizeof *attr);
1297   if (!attr)
1298     return errno;
1299
1300   attr->kind = NPTH_RWLOCK_DEFAULT_NP;
1301   *attr_r = attr;
1302   return 0;
1303 }
1304
1305
1306 int
1307 npth_rwlockattr_destroy (npth_rwlockattr_t *attr)
1308 {
1309   free (*attr);
1310   *attr = NULL;
1311   return 0;
1312 }
1313
1314
1315 int
1316 npth_rwlockattr_gettype_np (const npth_rwlockattr_t *attr,
1317                             int *kind)
1318 {
1319   *kind = (*attr)->kind;
1320   return 0;
1321 }
1322
1323
1324 int
1325 npth_rwlockattr_settype_np (npth_rwlockattr_t *attr, int kind)
1326 {
1327   if (kind != NPTH_RWLOCK_PREFER_READER_NP
1328       && kind != NPTH_RWLOCK_PREFER_WRITER_NP
1329       && kind != NPTH_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)
1330     return EINVAL;
1331
1332   (*attr)->kind = kind;
1333   return 0;
1334 }
1335
1336
1337 struct npth_rwlock_s
1338 {
1339   /* Objects are protected by the global lock, so no lock here
1340      necessary.  This is even true for the condition (by specifying
1341      NULL as the mutex in npth_cond_wait and npth_cond_timedwait).  */
1342
1343   /* True if we prefer writers over readers.  */
1344   int prefer_writer;
1345
1346   /* Readers who want the lock wait on this condition, which is
1347      broadcast when the last writer goes away.  */
1348   npth_cond_t reader_wait;
1349
1350   /* The number of readers waiting on the condition.  */
1351   int nr_readers_queued;
1352
1353   /* The number of current readers.  */
1354   int nr_readers;
1355
1356   /* Writers who want the lock wait on this condition, which is
1357      signaled when the current writer or last reader goes away.  */
1358   npth_cond_t writer_wait;
1359
1360   /* The number of queued writers.  */
1361   int nr_writers_queued;
1362
1363   /* The number of current writers.  This is either 1 (then nr_readers
1364      is 0) or it is 0.  At unlock time this value tells us if the
1365      current lock holder is a writer or a reader.  */
1366   int nr_writers;
1367 };
1368
1369
1370 int
1371 npth_rwlock_init (npth_rwlock_t *rwlock_r,
1372                   const npth_rwlockattr_t *user_attr)
1373 {
1374   int err;
1375   npth_rwlock_t rwlock;
1376   npth_rwlockattr_t attr;
1377   int attr_allocated;
1378
1379   if (user_attr != NULL)
1380     {
1381       attr = *user_attr;
1382       attr_allocated = 0;
1383     }
1384   else
1385     {
1386       err = npth_rwlockattr_init (&attr);
1387       if (err)
1388         return err;
1389     }
1390
1391   /* We can not check *rwlock_r here, as it may contain random data.  */
1392   rwlock = malloc (sizeof (*rwlock));
1393   if (!rwlock)
1394     {
1395       err = errno;
1396       goto err_out;
1397     }
1398
1399   rwlock->prefer_writer = (attr->kind == NPTH_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
1400
1401   err = npth_cond_init (&rwlock->reader_wait, NULL);
1402   if (err)
1403     {
1404       free (rwlock);
1405       goto err_out;
1406     }
1407
1408   err = npth_cond_init (&rwlock->writer_wait, NULL);
1409   if (err)
1410     {
1411       npth_cond_destroy (&rwlock->reader_wait);
1412       free (rwlock);
1413       goto err_out;
1414     }
1415
1416   rwlock->nr_readers = 0;
1417   rwlock->nr_readers_queued = 0;
1418   rwlock->nr_writers = 0;
1419   rwlock->nr_writers_queued = 0;
1420
1421   *rwlock_r = rwlock;
1422
1423  err_out:
1424   if (attr_allocated)
1425     npth_rwlockattr_destroy (&attr);
1426   return err;
1427 }
1428
1429
1430 /* Must be called with global lock held.  */
1431 static int
1432 rwlock_init_check (npth_rwlock_t *rwlock)
1433 {
1434   int err;
1435   npth_rwlockattr_t attr;
1436   int kind;
1437
1438   if (*rwlock == 0)
1439     return EINVAL;
1440
1441   if ((*rwlock) == NPTH_RWLOCK_INITIALIZER)
1442     kind = NPTH_RWLOCK_PREFER_READER_NP;
1443   if ((*rwlock) == NPTH_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP)
1444     kind = NPTH_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP;
1445   else
1446     /* Already initialized.  */
1447     return 0;
1448
1449   /* Make sure we don't try again in case of error.  */
1450   *rwlock = 0;
1451
1452   err = npth_rwlockattr_init (&attr);
1453   if (err)
1454     return err;
1455
1456   err = npth_rwlockattr_settype_np (&attr, kind);
1457   if (err)
1458     {
1459       npth_rwlockattr_destroy (&attr);
1460       return err;
1461     }
1462
1463   err = npth_rwlock_init (rwlock, &attr);
1464   npth_rwlockattr_destroy (&attr);
1465
1466   return err;
1467 }
1468
1469
1470 int
1471 npth_rwlock_destroy (npth_rwlock_t *rwlock)
1472 {
1473   int err;
1474
1475   if (*rwlock == 0 || *rwlock == NPTH_RWLOCK_INITIALIZER)
1476     return EINVAL;
1477
1478   if ((*rwlock)->nr_writers || (*rwlock)->nr_readers || (*rwlock)->nr_writers_queued
1479       || (*rwlock)->nr_readers_queued)
1480     return EBUSY;
1481
1482   err = npth_cond_destroy (&(*rwlock)->reader_wait);
1483   if (err)
1484     /* FIXME: Log this.  */
1485     ;
1486
1487   err = npth_cond_destroy (&(*rwlock)->writer_wait);
1488   if (err)
1489     /* FIXME: Log this.  */
1490     ;
1491
1492   free (rwlock);
1493
1494   *rwlock = NULL;
1495   return 0;
1496 }
1497
1498
1499 int
1500 npth_rwlock_tryrdlock (npth_rwlock_t *rwlock)
1501 {
1502   if ((*rwlock)->nr_writers)
1503     return EBUSY;
1504
1505   if ((*rwlock)->nr_writers_queued && (*rwlock)->prefer_writer)
1506     return EBUSY;
1507
1508   (*rwlock)->nr_readers++;
1509   return 0;
1510 }
1511
1512
1513 int
1514 npth_rwlock_rdlock (npth_rwlock_t *rwlock)
1515 {
1516   int err;
1517
1518   while (1)
1519     {
1520       /* Quick check.  */
1521       err = npth_rwlock_tryrdlock (rwlock);
1522       if (err != EBUSY)
1523         return err;
1524
1525       (*rwlock)->nr_readers_queued++;
1526       err = npth_cond_wait (&(*rwlock)->reader_wait, NULL);
1527       (*rwlock)->nr_readers_queued--;
1528       if (err)
1529         return err;
1530     }
1531 }
1532
1533 int
1534 npth_rwlock_timedrdlock (npth_rwlock_t *rwlock,
1535                          const struct timespec *abstime)
1536 {
1537   int err;
1538
1539   while (1)
1540     {
1541       /* Quick check.  */
1542       err = npth_rwlock_tryrdlock (rwlock);
1543       if (err != EBUSY)
1544         return err;
1545
1546       (*rwlock)->nr_readers_queued++;
1547       err = npth_cond_timedwait (&(*rwlock)->reader_wait, NULL, abstime);
1548       (*rwlock)->nr_readers_queued--;
1549       if (err)
1550         return err;
1551     }
1552 }
1553
1554 int
1555 npth_rwlock_trywrlock (npth_rwlock_t *rwlock)
1556 {
1557   if ((*rwlock)->nr_writers)
1558     return EBUSY;
1559
1560   if ((*rwlock)->nr_readers)
1561     return EBUSY;
1562
1563   (*rwlock)->nr_writers = 1;
1564   return 0;
1565 }
1566
1567
1568 int
1569 npth_rwlock_wrlock (npth_rwlock_t *rwlock)
1570 {
1571   int err;
1572
1573   while (1)
1574     {
1575       /* Quick check.  */
1576       err = npth_rwlock_trywrlock (rwlock);
1577       if (err != EBUSY)
1578         return err;
1579
1580       (*rwlock)->nr_writers_queued++;
1581       err = npth_cond_wait (&(*rwlock)->writer_wait, NULL);
1582       (*rwlock)->nr_writers_queued--;
1583       if (err)
1584         return err;
1585     }
1586 }
1587
1588
1589 int
1590 npth_rwlock_timedwrlock (npth_rwlock_t *rwlock,
1591                          const struct timespec *abstime)
1592 {
1593   int err;
1594
1595   while (1)
1596     {
1597       /* Quick check.  */
1598       err = npth_rwlock_trywrlock (rwlock);
1599       if (err != EBUSY)
1600         return err;
1601
1602       (*rwlock)->nr_writers_queued++;
1603       err = npth_cond_timedwait (&(*rwlock)->writer_wait, NULL, abstime);
1604       (*rwlock)->nr_writers_queued--;
1605       if (err)
1606         return err;
1607     }
1608 }
1609
1610
1611 int
1612 npth_rwlock_unlock (npth_rwlock_t *rwlock)
1613 {
1614   int err;
1615
1616   if ((*rwlock)->nr_writers)
1617     /* We are the writer.  */
1618     (*rwlock)->nr_writers = 0;
1619   else
1620     /* We are the reader.  */
1621     (*rwlock)->nr_readers--;
1622
1623   if ((*rwlock)->nr_readers == 0)
1624     {
1625       if ((*rwlock)->nr_writers_queued)
1626         {
1627           err = npth_cond_signal (&(*rwlock)->writer_wait);
1628           if (err)
1629             return err;
1630         }
1631       else if ((*rwlock)->nr_readers_queued)
1632         {
1633           err = npth_cond_broadcast (&(*rwlock)->reader_wait);
1634           return err;
1635         }
1636     }
1637   return 0;
1638 }
1639
1640 \f
1641 /* Standard POSIX Replacement API */
1642
1643 int
1644 npth_usleep(unsigned int usec)
1645 {
1646   ENTER();
1647   Sleep((usec + 999) / 1000);
1648   LEAVE();
1649   return 0;
1650 }
1651
1652
1653 unsigned int
1654 npth_sleep(unsigned int sec)
1655 {
1656   ENTER();
1657   Sleep (sec * 1000);
1658   LEAVE();
1659   return 0;
1660 }
1661
1662
1663 int
1664 npth_system(const char *cmd)
1665 {
1666   int res;
1667
1668   ENTER();
1669   res = system(cmd);
1670   LEAVE();
1671   return res;
1672 }
1673
1674
1675 pid_t
1676 npth_waitpid(pid_t pid, int *status, int options)
1677 {
1678   return EOPNOTSUPP;
1679 }
1680
1681
1682 int
1683 npth_connect(int s, const struct sockaddr *addr, socklen_t addrlen)
1684 {
1685   int res;
1686
1687   ENTER();
1688   res = connect(s, addr, addrlen);
1689   LEAVE();
1690   return res;
1691 }
1692
1693
1694 int
1695 npth_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1696 {
1697   int res;
1698
1699   ENTER();
1700   res = accept(s, addr, addrlen);
1701   LEAVE();
1702   return res;
1703 }
1704
1705
1706 int
1707 npth_select(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
1708             struct timeval *timeout)
1709 {
1710   int res;
1711
1712   ENTER();
1713   res = select(nfd, rfds, wfds, efds, timeout);
1714   LEAVE();
1715   return res;
1716 }
1717
1718
1719 ssize_t
1720 npth_read(int fd, void *buf, size_t nbytes)
1721 {
1722   ssize_t res;
1723
1724   ENTER();
1725   res = read(fd, buf, nbytes);
1726   LEAVE();
1727   return res;
1728 }
1729
1730
1731 ssize_t
1732 npth_write(int fd, const void *buf, size_t nbytes)
1733 {
1734   ssize_t res;
1735
1736   ENTER();
1737   res = write(fd, buf, nbytes);
1738   LEAVE();
1739   return res;
1740 }
1741
1742
1743 int
1744 npth_recvmsg (int fd, struct msghdr *msg, int flags)
1745 {
1746   return EOPNOTSUPP;
1747 }
1748
1749
1750 int
1751 npth_sendmsg (int fd, const struct msghdr *msg, int flags)
1752 {
1753   return EOPNOTSUPP;
1754 }
1755
1756
1757 void
1758 npth_unprotect (void)
1759 {
1760   /* If we are not initialized we may not access the semaphore and
1761    * thus we shortcut it. Note that in this case the unprotect/protect
1762    * is not needed.  For failsafe reasons if an nPth thread has ever
1763    * been created but nPth has accidentally not initialized we do not
1764    * shortcut so that a stack backtrace (due to the access of the
1765    * uninitialized semaphore) is more expressive.  */
1766   if (initialized_or_any_threads)
1767     ENTER();
1768 }
1769
1770
1771 void
1772 npth_protect (void)
1773 {
1774   /* See npth_unprotect for commentary.  */
1775   if (initialized_or_any_threads)
1776     LEAVE();
1777 }
1778
1779
1780 int
1781 npth_is_protected (void)
1782 {
1783   return got_sceptre;
1784 }
1785
1786
1787 \f
1788 /* Maximum number of extra handles.  We can only support 31 as that is
1789    the number of bits we can return.  This is smaller than the maximum
1790    number of allowed wait objects for WFMO (which is 64).  */
1791 #define MAX_EVENTS 31
1792
1793 /* Although the WSAEventSelect machinery seems to have no limit on the
1794    number of selectable fds, we impose the same limit as used by
1795    traditional select.  This allows us to work with a static data
1796    structure instead of an dynamically allocated array.  */
1797 #define MAX_FDOBJS FD_SETSIZE
1798
1799 /* Using WFMO even for sockets makes Windows objects more composable,
1800    which helps faking signals and other constructs, so we support
1801    that.  You can still use npth_select for the plain select
1802    function.  */
1803 int
1804 npth_eselect(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
1805              const struct timespec *timeout,
1806              HANDLE *events, unsigned int *events_set)
1807 {
1808   int err = 0;
1809   DWORD msecs;
1810   int i;
1811   u_int idx;
1812   /* One more for the handle associated with socket events.  */
1813   HANDLE obj[MAX_EVENTS + 1];
1814   int nr_obj = 0;
1815   /* Number of extra events.  */
1816   int nr_events = 0;
1817   HANDLE sock_event = INVALID_HANDLE_VALUE;
1818   /* This will be (nr_obj - 1) == nr_events.  */
1819   int sock_event_idx = -1;
1820   int res;
1821   DWORD ret;
1822   SOCKET fd;
1823   long flags;
1824   int cnt;
1825   struct {
1826     SOCKET fd;
1827     long flags;
1828   } fdobj[MAX_FDOBJS];
1829   int nr_fdobj = 0;
1830
1831   (void)nfd;  /* No need for it under Windows.  */
1832
1833   if (events)
1834     {
1835       if (!events_set)
1836         {
1837           errno = EINVAL;
1838           return -1;
1839         }
1840
1841       /* We always ensure that the events_set is valid, even after an
1842          error.  */
1843       *events_set = 0;
1844     }
1845
1846   if (timeout && (timeout->tv_sec < 0 || timeout->tv_nsec < 0))
1847     {
1848       errno = EINVAL;
1849       return -1;
1850     }
1851
1852   if (timeout == NULL)
1853     msecs = INFINITE;
1854   else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0)
1855     msecs = 0;
1856   else
1857     {
1858       msecs = (timeout->tv_sec * 1000) + (timeout->tv_nsec + 999999) / 1000000;
1859       if (msecs < 1)
1860         msecs = 1;
1861     }
1862
1863   if (events)
1864     {
1865       /* Copy the extra handles.  */
1866       for (i = 0; i < MAX_EVENTS; i++)
1867         {
1868           if (events[i] == INVALID_HANDLE_VALUE)
1869             break;
1870
1871           obj[nr_obj] = events[i];
1872           nr_obj++;
1873           nr_events++;
1874         }
1875
1876       /* We can only return the status of up to MAX_EVENTS handles in
1877          EVENTS_SET.  */
1878       if (events[i] != INVALID_HANDLE_VALUE)
1879         {
1880           errno = EINVAL;
1881           return -1;
1882         }
1883     }
1884
1885   /* From here on, we clean up at err_out, and you can set ERR to
1886      return an error.  */
1887
1888   sock_event = WSACreateEvent ();
1889   if (sock_event == INVALID_HANDLE_VALUE)
1890     {
1891       err = EINVAL;
1892       return -1;
1893     }
1894
1895   sock_event_idx = nr_obj;
1896   obj[nr_obj] = sock_event;
1897   nr_obj++;
1898
1899   /* Combine FDs from all lists.  */
1900 #define SET_FDOBJ(x,v) do {                      \
1901     for (idx=0; idx < (x)->fd_count; idx++)      \
1902       {                                          \
1903         for (i=0; i < nr_fdobj; i++)             \
1904           if (fdobj[i].fd == (x)->fd_array[idx]) \
1905             break;                               \
1906         if (i < nr_fdobj)                        \
1907           ;                                      \
1908         else if (nr_fdobj < MAX_FDOBJS)          \
1909           {                                      \
1910             i = nr_fdobj++;                      \
1911             fdobj[i].fd    = (x)->fd_array[idx]; \
1912             fdobj[i].flags = 0;                  \
1913           }                                      \
1914         else                                     \
1915           {                                      \
1916             err = EINVAL;                        \
1917             goto err_out;                        \
1918           }                                      \
1919         fdobj[i].flags |= (v);                   \
1920       }                                          \
1921   } while (0)
1922
1923   if (rfds)
1924     SET_FDOBJ (rfds, FD_READ | FD_ACCEPT);
1925   if (wfds)
1926     SET_FDOBJ (wfds, FD_WRITE);
1927   if (efds)
1928     SET_FDOBJ (efds, FD_OOB | FD_CLOSE);
1929
1930 #undef SET_FDOBJ
1931
1932   /* Set the select flags.  */
1933   for (i = 0; i < nr_fdobj; i++)
1934     {
1935       res = WSAEventSelect (fdobj[i].fd, sock_event, fdobj[i].flags);
1936       if (res == SOCKET_ERROR)
1937         {
1938           err = map_error (WSAGetLastError());
1939           goto err_out;
1940         }
1941     }
1942
1943   /* Let's wait.  */
1944   ENTER();
1945   ret = WaitForMultipleObjects (nr_obj, obj, FALSE, msecs);
1946   LEAVE();
1947   if (ret == WAIT_TIMEOUT)
1948     {
1949       err = ETIMEDOUT;
1950       goto err_out;
1951     }
1952   else if (ret == WAIT_FAILED)
1953     {
1954       err = map_error (GetLastError());
1955       goto err_out;
1956     }
1957
1958   /* All other return values: We look at the objects.  We must not
1959      fail from here, because then we could lose events.  */
1960
1961   /* Keep track of result count.  */
1962   cnt = 0;
1963
1964   for (i = 0; i < nr_events; i++)
1965     {
1966       ret = WaitForSingleObject (obj[i], 0);
1967       if (ret != WAIT_OBJECT_0)
1968         /* We ignore errors here.  */
1969         continue;
1970
1971       *events_set = (*events_set) | (1 << i);
1972       /* We consume the event here.  This may be undesirable, but
1973          unless we make it configurable we need a common policy,
1974          and this saves the user one step.  */
1975       ResetEvent (obj[i]);
1976       /* Increase result count.  */
1977       cnt++;
1978     }
1979
1980   /* Now update the file descriptors sets.  */
1981   if (rfds)
1982     FD_ZERO (rfds);
1983   if (wfds)
1984     FD_ZERO (wfds);
1985   if (efds)
1986     FD_ZERO (efds);
1987   for (i = 0; i < nr_fdobj; i++)
1988     {
1989       WSANETWORKEVENTS ne;
1990
1991       fd = fdobj[i].fd;
1992       flags = fdobj[i].flags;
1993
1994       res = WSAEnumNetworkEvents (fd, NULL, &ne);
1995       if (res == SOCKET_ERROR)
1996         continue; /* FIXME: We ignore this error here.  */
1997
1998       /* NB that the test on FLAGS guarantees that ?fds is not NULL. */
1999       if ((flags & FD_READ) && (ne.lNetworkEvents & (FD_READ | FD_ACCEPT)))
2000         {
2001           FD_SET (fd, rfds);
2002           cnt++;
2003         }
2004       if ((flags & FD_WRITE) && (ne.lNetworkEvents & FD_WRITE))
2005         {
2006           FD_SET (fd, wfds);
2007           cnt++;
2008         }
2009       if ((flags & FD_CLOSE) && (ne.lNetworkEvents & (FD_OOB | FD_CLOSE)))
2010         {
2011           FD_SET (fd, efds);
2012           cnt++;
2013         }
2014
2015       WSAEventSelect (fd, NULL, 0); /* We ignore errors.  */
2016     }
2017
2018   /* We ignore errors.  */
2019   WSACloseEvent (sock_event);
2020
2021   return cnt;
2022
2023   /* Cleanup.  */
2024  err_out:
2025   if (sock_event != INVALID_HANDLE_VALUE)
2026     {
2027       for (i = 0; i < nr_fdobj; i++)
2028         {
2029           WSAEventSelect (fdobj[i].fd, NULL, 0); /* We ignore errors.  */
2030         }
2031       WSACloseEvent (sock_event); /* We ignore errors.  */
2032     }
2033
2034   if (err == ETIMEDOUT)
2035     return 0;
2036
2037   errno = err;
2038   return -1;
2039 }