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