489b28300e7a3c62830acb1a5e63bee8e657a1fb
[gnupg.git] / jnlib / w32-pth.c
1 /* w32-pth.c - GNU Pth emulation for W32 (MS Windows).
2  * Copyright (c) 1999-2003 Ralf S. Engelschall <rse@engelschall.com>
3  * Copyright (C) 2004 g10 Code GmbH
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20  *
21  * ------------------------------------------------------------------
22  * This code is based on Ralf Engelschall's GNU Pth, a non-preemptive
23  * thread scheduling library which can be found at
24  * http://www.gnu.org/software/pth/.  MS Windows (W32) specific code
25  * written by Timo Schulz, g10 Code.
26  */
27
28 #include <config.h>
29 #ifdef HAVE_W32_SYSTEM
30 #include <windows.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <io.h>
34 #include <signal.h>
35
36 #include "logging.h" /* For log_get_prefix () */
37
38 /* We don't want to have any Windows specific code in the header, thus
39    we use a macro which defaults to a compatible type in w32-pth.h. */
40 #define W32_PTH_HANDLE_INTERNAL  HANDLE
41 #include "w32-pth.h"
42
43 #define DEBUG_ENTER_LEAVE 1 /* Set to 1 to enable full debugging. */
44
45
46 #ifndef FALSE
47 #define FALSE 0
48 #endif
49 #ifndef TRUE
50 #define TRUE 1
51 #endif
52 #if FALSE != 0 || TRUE != 1 
53 #error TRUE or FALSE defined to wrong values
54 #endif
55
56
57 /* States whether trhis module has been initialized.  */
58 static int pth_initialized;
59
60 /* Controls whether debugging is enabled.  */
61 static int debug_enter_leave;
62
63 /* Variables to support event handling. */
64 static int pth_signo;
65 static HANDLE pth_signo_ev;
66
67 /* Mutex to make sure only one thread is running. */
68 static CRITICAL_SECTION pth_shd;
69
70
71
72 struct pth_event_s
73 {
74   struct pth_event_s * next;
75   struct pth_event_s * prev;
76   HANDLE hd;
77   union
78   {
79     struct sigset_s * sig;
80     int               fd;
81     struct timeval    tv;
82     pth_mutex_t     * mx;
83   } u;
84   int * val;
85   int u_type;
86   int flags;
87 };
88
89
90 struct pth_attr_s 
91 {
92   unsigned int flags;
93   unsigned int stack_size;
94   char * name;
95 };
96
97
98 /* Object to keep information about a thread.  This may eventually be
99    used to implement a scheduler queue.  */
100 struct thread_info_s
101 {
102   void *(*thread)(void *); /* The actual thread fucntion.  */
103   void * arg;              /* The argument passed to that fucntion.  */
104   int joinable;            /* True if this Thread is joinable.  */
105   HANDLE th;               /* Handle of this thread.  Used by non-joinable
106                               threads to close the handle.  */
107 };
108
109
110 /* Convenience macro to startup the system.  */
111 #define implicit_init() do { if (!pth_initialized) pth_init(); } while (0)
112
113 /* Prototypes.  */
114 static pth_event_t do_pth_event (unsigned long spec, ...);
115 static unsigned int do_pth_waitpid (unsigned pid, int * status, int options);
116 static int do_pth_wait (pth_event_t ev);
117 static int do_pth_event_status (pth_event_t ev);
118 static void *launch_thread (void * ctx);
119
120
121
122 \f
123 int
124 pth_init (void)
125 {
126   SECURITY_ATTRIBUTES sa;
127   WSADATA wsadat;
128   
129   if (pth_initialized)
130     return TRUE;
131
132   fprintf (stderr, "%s: pth_init: called.\n", log_get_prefix (NULL));
133   debug_enter_leave = !!getenv ("DEBUG_PTH");
134
135   if (WSAStartup (0x202, &wsadat))
136     return FALSE;
137   pth_signo = 0;
138   InitializeCriticalSection (&pth_shd);
139   if (pth_signo_ev)
140     CloseHandle (pth_signo_ev);
141   memset (&sa, 0, sizeof sa);
142   sa.bInheritHandle = TRUE;
143   sa.lpSecurityDescriptor = NULL;
144   sa.nLength = sizeof sa;
145   pth_signo_ev = CreateEvent (&sa, TRUE, FALSE, NULL);
146   if (!pth_signo_ev)
147     return FALSE;
148
149   pth_initialized = 1;
150   EnterCriticalSection (&pth_shd);
151   return TRUE;
152 }
153
154
155 int
156 pth_kill (void)
157 {
158   pth_signo = 0;
159   if (pth_signo_ev)
160     {
161       CloseHandle (pth_signo_ev);
162       pth_signo_ev = NULL;
163     }
164   if (pth_initialized)
165     DeleteCriticalSection (&pth_shd);
166   WSACleanup ();
167   pth_initialized = 0;
168   return TRUE;
169 }
170
171
172 static char *
173 w32_strerror (char *strerr, size_t strerrsize)
174 {
175   if (strerrsize > 1)
176     FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, (int)GetLastError (),
177                    MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
178                    strerr, strerrsize, NULL);
179   return strerr;
180 }
181
182
183 static void
184 enter_pth (const char *function)
185 {
186   /* Fixme: I am not sure whether the same thread my enter a critical
187      section twice.  */
188   if (debug_enter_leave)
189     fprintf (stderr, "%s: enter_pth (%s)\n",
190              log_get_prefix (NULL), function? function:"");
191   LeaveCriticalSection (&pth_shd);
192 }
193
194
195 static void
196 leave_pth (const char *function)
197 {
198   EnterCriticalSection (&pth_shd);
199   if (debug_enter_leave)
200     fprintf (stderr, "%s: leave_pth (%s)\n",
201              log_get_prefix (NULL), function? function:"");
202 }
203
204
205 long 
206 pth_ctrl (unsigned long query, ...)
207 {
208   implicit_init ();
209
210   switch (query)
211     {
212     case PTH_CTRL_GETAVLOAD:
213     case PTH_CTRL_GETPRIO:
214     case PTH_CTRL_GETNAME:
215     case PTH_CTRL_GETTHREADS_NEW:
216     case PTH_CTRL_GETTHREADS_READY:
217     case PTH_CTRL_GETTHREADS_RUNNING:
218     case PTH_CTRL_GETTHREADS_WAITING:
219     case PTH_CTRL_GETTHREADS_SUSPENDED:
220     case PTH_CTRL_GETTHREADS_DEAD:
221     case PTH_CTRL_GETTHREADS:
222     default:
223       return -1;
224     }
225   return 0;
226 }
227
228
229
230 pth_time_t
231 pth_timeout (long sec, long usec)
232 {
233   pth_time_t tvd;
234
235   tvd.tv_sec  = sec;
236   tvd.tv_usec = usec;    
237   return tvd;
238 }
239
240
241 int
242 pth_read_ev (int fd, void *buffer, size_t size, pth_event_t ev)
243 {
244   implicit_init ();
245   return 0;
246 }
247
248
249 int
250 pth_read (int fd,  void * buffer, size_t size)
251 {
252   int n;
253
254   implicit_init ();
255   enter_pth (__FUNCTION__);
256
257   n = recv (fd, buffer, size, 0);
258   if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
259     {
260       DWORD nread = 0;
261       n = ReadFile ((HANDLE)fd, buffer, size, &nread, NULL);
262       if (!n)
263         {
264           char strerr[256];
265
266           fprintf (stderr, "%s: pth_read(%d) failed read from file: %s\n",
267                    log_get_prefix (NULL), fd,
268                    w32_strerror (strerr, sizeof strerr));
269           n = -1;
270         }
271       else
272         n = (int)nread;
273     }
274   leave_pth (__FUNCTION__);
275   return n;
276 }
277
278
279 int
280 pth_write_ev (int fd, const void *buffer, size_t size, pth_event_t ev)
281 {
282   implicit_init ();
283   return 0;
284 }
285
286
287 int
288 pth_write (int fd, const void * buffer, size_t size)
289 {
290   int n;
291
292   implicit_init ();
293   enter_pth (__FUNCTION__);
294   n = send (fd, buffer, size, 0);
295   if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
296     {
297       DWORD nwrite;
298       char strerr[256];
299
300       /* This is no real error because we first need to figure out if
301          we have a handle or a socket.  */
302
303       n = WriteFile ((HANDLE)fd, buffer, size, &nwrite, NULL);
304       if (!n)
305         {
306           fprintf (stderr, "%s: pth_write(%d) failed in write: %s\n",
307                    log_get_prefix (NULL), fd,
308                    w32_strerror (strerr, sizeof strerr));
309           fprintf (stderr, "--> fd = %d, handle = %p, size = %lu\n",
310                    fd, (HANDLE)fd, size);
311           n = -1;
312         }
313       else
314         n = (int)nwrite;
315     }
316   leave_pth (__FUNCTION__);
317   return n;
318 }
319
320
321 int
322 pth_select (int nfds, fd_set * rfds, fd_set * wfds, fd_set * efds,
323             const struct timeval * timeout)
324 {
325   int n;
326
327   implicit_init ();
328   enter_pth (__FUNCTION__);
329   n = select (nfds, rfds, wfds, efds, timeout);
330   leave_pth (__FUNCTION__);
331   return n;
332 }
333
334
335 int
336 pth_fdmode (int fd, int mode)
337 {
338   unsigned long val;
339   int ret = PTH_FDMODE_BLOCK;
340
341   implicit_init ();
342   /* Note: we don't do the eter/leave pth here because this is for one
343      a fast fucntion and secondly already called from inside such a
344      block.  */
345   /* XXX: figure out original fd mode */
346   switch (mode)
347     {
348     case PTH_FDMODE_NONBLOCK:
349       val = 1;
350       if (ioctlsocket (fd, FIONBIO, &val) == SOCKET_ERROR)
351         ret = PTH_FDMODE_ERROR;
352       break;
353
354     case PTH_FDMODE_BLOCK:
355       val = 0;
356       if (ioctlsocket (fd, FIONBIO, &val) == SOCKET_ERROR)
357         ret = PTH_FDMODE_ERROR;
358       break;
359     }
360   return ret;
361 }
362
363
364 int
365 pth_accept (int fd, struct sockaddr *addr, int *addrlen)
366 {
367   int rc;
368
369   implicit_init ();
370   enter_pth (__FUNCTION__);
371   rc = accept (fd, addr, addrlen);
372   leave_pth (__FUNCTION__);
373   return rc;
374 }
375
376
377 int
378 pth_accept_ev (int fd, struct sockaddr *addr, int *addrlen,
379                pth_event_t ev_extra)
380 {
381   pth_key_t ev_key;
382   pth_event_t ev;
383   int rv;
384   int fdmode;
385
386   implicit_init ();
387   enter_pth (__FUNCTION__);
388
389   fdmode = pth_fdmode (fd, PTH_FDMODE_NONBLOCK);
390   if (fdmode == PTH_FDMODE_ERROR)
391     {
392       leave_pth (__FUNCTION__);
393       return -1;
394     }
395
396   ev = NULL;
397   while ((rv = accept (fd, addr, addrlen)) == -1 && 
398          (WSAGetLastError () == WSAEINPROGRESS || 
399           WSAGetLastError () == WSAEWOULDBLOCK))
400     {
401       if (ev == NULL)
402         {
403           ev = do_pth_event (PTH_EVENT_FD|PTH_UNTIL_FD_READABLE|
404                              PTH_MODE_STATIC, &ev_key, fd);
405           if (ev == NULL)
406             {
407               leave_pth (__FUNCTION__);
408               return -1;
409             }
410           if (ev_extra != NULL)
411             pth_event_concat (ev, ev_extra, NULL);
412         }
413       /* Wait until accept has a chance. */
414       do_pth_wait (ev);
415       if (ev_extra != NULL)
416         {
417           pth_event_isolate (ev);
418           if (do_pth_event_status (ev) != PTH_STATUS_OCCURRED)
419             {
420               pth_fdmode (fd, fdmode);
421               leave_pth (__FUNCTION__);
422               return -1;
423             }
424         }
425     }
426
427   pth_fdmode (fd, fdmode);
428   leave_pth (__FUNCTION__);
429   return rv;   
430 }
431
432
433 int
434 pth_connect (int fd, struct sockaddr *name, int namelen)
435 {
436   int rc;
437
438   implicit_init ();
439   enter_pth (__FUNCTION__);
440   rc = connect (fd, name, namelen);
441   leave_pth (__FUNCTION__);
442   return rc;
443 }
444
445
446 int
447 pth_mutex_release (pth_mutex_t *hd)
448 {
449   if (!hd)
450     return -1;
451   implicit_init ();
452   enter_pth (__FUNCTION__);
453   if (hd->mx)
454     {
455       CloseHandle (hd->mx);
456       hd->mx = NULL;
457     }
458   free (hd);
459   leave_pth (__FUNCTION__);
460   return 0;
461 }
462
463
464 int
465 pth_mutex_acquire (pth_mutex_t *hd, int tryonly, pth_event_t ev_extra)
466 {
467   implicit_init ();
468   enter_pth (__FUNCTION__);
469
470   if (!hd || !hd->mx)
471     {
472       leave_pth (__FUNCTION__);
473       return FALSE;
474     }
475     
476 #if 0
477   /* still not locked, so simply acquire mutex? */
478   if (!(mutex->mx_state & PTH_MUTEX_LOCKED))
479     {
480       mutex->mx_state |= PTH_MUTEX_LOCKED;
481       mutex->mx_count = 1;
482       pth_ring_append(&(pth_current->mutexring), &(mutex->mx_node));
483       pth_debug1("pth_mutex_acquire: immediately locking mutex");
484       return 0;
485     }
486
487   /* already locked by caller? */
488   if (mutex->mx_count >= 1 && mutex->mx_owner == pth_current)
489     {
490       /* recursive lock */
491       mutex->mx_count++;
492       pth_debug1("pth_mutex_acquire: recursive locking");
493       return 0;
494     }
495
496   if (tryonly)
497     {
498       leave_pth (__FUNCTION__);
499       return -1;
500     }
501
502   for (;;)
503     {
504       ev = pth_event(PTH_EVENT_MUTEX|PTH_MODE_STATIC, &ev_key, mutex);
505       if (ev_extra != NULL)
506         pth_event_concat (ev, ev_extra, NULL);
507       pth_wait (ev);
508       if (ev_extra != NULL)
509         {
510           pth_event_isolate (ev);
511           if (do_pth_event_status(ev) == PTH_STATUS_PENDING)
512             {
513               leave_pth (__FUNCTION__);
514               return -1;
515             }
516         }
517       if (!(mutex->mx_state & PTH_MUTEX_LOCKED))
518         break;
519     }
520 #endif
521
522   hd->mx_state |= PTH_MUTEX_LOCKED;
523   leave_pth (__FUNCTION__);
524   return TRUE;
525 }
526
527
528 int
529 pth_mutex_init (pth_mutex_t *hd)
530 {
531   SECURITY_ATTRIBUTES sa;
532   
533   implicit_init ();
534   enter_pth (__FUNCTION__);
535
536   if (hd->mx)
537     {
538       ReleaseMutex (hd->mx);
539       CloseHandle (hd->mx);
540     }
541   memset (&sa, 0, sizeof sa);
542   sa.bInheritHandle = TRUE;
543   sa.lpSecurityDescriptor = NULL;
544   sa.nLength = sizeof sa;
545   hd->mx = CreateMutex (&sa, FALSE, NULL);
546   hd->mx_state = PTH_MUTEX_INITIALIZED;
547
548   leave_pth (__FUNCTION__);
549   return TRUE;
550 }
551
552
553 pth_attr_t
554 pth_attr_new (void)
555 {
556   pth_attr_t hd;
557
558   implicit_init ();
559   hd = calloc (1, sizeof *hd);
560   return hd;
561 }
562
563
564 int
565 pth_attr_destroy (pth_attr_t hd)
566 {
567   if (!hd)
568     return -1;
569   implicit_init ();
570   if (hd->name)
571     free (hd->name);
572   free (hd);
573   return TRUE;
574 }
575
576
577 int
578 pth_attr_set (pth_attr_t hd, int field, ...)
579 {    
580   va_list args;
581   char * str;
582   int val;
583   int rc = TRUE;
584
585   implicit_init ();
586
587   va_start (args, field);
588   switch (field)
589     {
590     case PTH_ATTR_JOINABLE:
591       val = va_arg (args, int);
592       if (val)
593         {
594           hd->flags |= PTH_ATTR_JOINABLE;
595           fprintf (stderr, "%s: pth_attr_set: PTH_ATTR_JOINABLE\n",
596                    log_get_prefix (NULL));
597         }
598       break;
599
600     case PTH_ATTR_STACK_SIZE:
601       val = va_arg (args, int);
602       if (val)
603         {
604           hd->flags |= PTH_ATTR_STACK_SIZE;
605           hd->stack_size = val;
606           fprintf (stderr, "%s: pth_attr_set: PTH_ATTR_STACK_SIZE %d\n",
607                    log_get_prefix (NULL), val);
608         }
609       break;
610
611     case PTH_ATTR_NAME:
612       str = va_arg (args, char*);
613       if (hd->name)
614         free (hd->name);
615       if (str)
616         {
617           hd->name = strdup (str);
618           if (!hd->name)
619             return FALSE;
620           hd->flags |= PTH_ATTR_NAME;
621           fprintf (stderr, "%s: pth_attr_set: PTH_ATTR_NAME %s\n",
622                    log_get_prefix (NULL), hd->name);
623         }
624       break;
625
626     default:
627       rc = FALSE;
628       break;
629     }
630   va_end (args);
631   return rc;
632 }
633
634
635 static pth_t
636 do_pth_spawn (pth_attr_t hd, void *(*func)(void *), void *arg)
637 {
638   SECURITY_ATTRIBUTES sa;
639   DWORD tid;
640   HANDLE th;
641   struct thread_info_s *ctx;
642
643   if (!hd)
644     return NULL;
645
646   memset (&sa, 0, sizeof sa);
647   sa.bInheritHandle = TRUE;
648   sa.lpSecurityDescriptor = NULL;
649   sa.nLength = sizeof sa;
650
651   ctx = calloc (1, sizeof *ctx);
652   if (!ctx)
653     return NULL;
654   ctx->thread = func;
655   ctx->arg = arg;
656   ctx->joinable = (hd->flags & PTH_ATTR_JOINABLE);
657
658   /* XXX: we don't use all thread attributes. */
659
660   /* Note that we create the thread suspended so that we are able to
661      store the thread's handle in the context structure.  We need to
662      do this to be able to close the handle from the launch helper. 
663
664      FIXME: We should no use th W32's Thread handle directly but keep
665      our own thread control structure.  CTX may be used for that.  */
666   fprintf (stderr, "%s: do_pth_spawn creating thread ...\n",
667            log_get_prefix (NULL));
668   th = CreateThread (&sa, hd->stack_size,
669                      (LPTHREAD_START_ROUTINE)launch_thread,
670                      ctx, CREATE_SUSPENDED, &tid);
671   ctx->th = th;
672   fprintf (stderr, "%s: do_pth_spawn created thread %p\n",
673            log_get_prefix (NULL),th);
674   if (!th)
675     free (ctx);
676   else
677     ResumeThread (th);
678   
679   return th;
680 }
681
682 pth_t
683 pth_spawn (pth_attr_t hd, void *(*func)(void *), void *arg)
684 {
685   HANDLE th;
686
687   if (!hd)
688     return NULL;
689
690   implicit_init ();
691   enter_pth (__FUNCTION__);
692   th = do_pth_spawn (hd, func, arg);
693   leave_pth (__FUNCTION__);
694   return th;
695 }
696
697
698 int
699 pth_join (pth_t hd, void **value)
700 {
701   return TRUE;
702 }
703
704
705 /* friendly */
706 int
707 pth_cancel (pth_t hd)
708 {
709   if (!hd)
710     return -1;
711   implicit_init ();
712   enter_pth (__FUNCTION__);
713   WaitForSingleObject (hd, 1000);
714   TerminateThread (hd, 0);
715   leave_pth (__FUNCTION__);
716   return TRUE;
717 }
718
719
720 /* cruel */
721 int
722 pth_abort (pth_t hd)
723 {
724   if (!hd)
725     return -1;
726   implicit_init ();
727   enter_pth (__FUNCTION__);
728   TerminateThread (hd, 0);
729   leave_pth (__FUNCTION__);
730   return TRUE;
731 }
732
733
734 void
735 pth_exit (void *value)
736 {
737   implicit_init ();
738   enter_pth (__FUNCTION__);
739   pth_kill ();
740   leave_pth (__FUNCTION__);
741   exit ((int)(long)value);
742 }
743
744
745 static unsigned int
746 do_pth_waitpid (unsigned pid, int * status, int options)
747 {
748 #if 0
749   pth_event_t ev;
750   static pth_key_t ev_key = PTH_KEY_INIT;
751   pid_t pid;
752
753   pth_debug2("pth_waitpid: called from thread \"%s\"", pth_current->name);
754
755   for (;;)
756     {
757       /* do a non-blocking poll for the pid */
758       while (   (pid = pth_sc(waitpid)(wpid, status, options|WNOHANG)) < 0
759                 && errno == EINTR)
760         ;
761
762       /* if pid was found or caller requested a polling return immediately */
763       if (pid == -1 || pid > 0 || (pid == 0 && (options & WNOHANG)))
764         break;
765
766       /* else wait a little bit */
767       ev = pth_event(PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key,
768                      pth_timeout (0,250000));
769       pth_wait(ev);
770     }
771
772   pth_debug2("pth_waitpid: leave to thread \"%s\"", pth_current->name);
773 #endif
774   return 0;
775 }
776
777
778 unsigned int
779 pth_waitpid (unsigned pid, int * status, int options)
780 {
781   unsigned int n;
782
783   implicit_init ();
784   enter_pth (__FUNCTION__);
785   n = do_pth_waitpid (pid, status, options);
786   leave_pth (__FUNCTION__);
787   return n;
788 }
789
790
791 static BOOL WINAPI
792 sig_handler (DWORD signo)
793 {
794   switch (signo)
795     {
796     case CTRL_C_EVENT:     pth_signo = SIGINT; break;
797     case CTRL_BREAK_EVENT: pth_signo = SIGTERM; break;
798     }
799   SetEvent (pth_signo_ev);
800   fprintf (stderr, "%s: sig_handler=%d\n", log_get_prefix (NULL), pth_signo);
801   return TRUE;
802 }
803
804
805 static pth_event_t
806 do_pth_event_body (unsigned long spec, va_list arg)
807 {
808   SECURITY_ATTRIBUTES sa;
809   pth_event_t ev;
810   int rc;
811
812   fprintf (stderr, "%s: pth_event spec=%lu\n", log_get_prefix (NULL), spec);
813   ev = calloc (1, sizeof *ev);
814   if (!ev)
815     return NULL;
816   if (spec == 0)
817     ;
818   else if (spec & PTH_EVENT_SIGS)
819     {
820       ev->u.sig = va_arg (arg, struct sigset_s *);
821       ev->u_type = PTH_EVENT_SIGS;
822       ev->val = va_arg (arg, int *);    
823       rc = SetConsoleCtrlHandler (sig_handler, TRUE);
824       fprintf (stderr, "%s: pth_event: sigs rc=%d\n",
825                log_get_prefix (NULL), rc);
826     }
827   else if (spec & PTH_EVENT_FD)
828     {
829       if (spec & PTH_UNTIL_FD_READABLE)
830         ev->flags |= PTH_UNTIL_FD_READABLE;
831       if (spec & PTH_MODE_STATIC)
832         ev->flags |= PTH_MODE_STATIC;
833       ev->u_type = PTH_EVENT_FD;
834       va_arg (arg, pth_key_t);
835       ev->u.fd = va_arg (arg, int);
836       fprintf (stderr, "%s: pth_event: fd=%d\n",
837                log_get_prefix (NULL), ev->u.fd);
838     }
839   else if (spec & PTH_EVENT_TIME)
840     {
841       pth_time_t t;
842       if (spec & PTH_MODE_STATIC)
843         ev->flags |= PTH_MODE_STATIC;
844       va_arg (arg, pth_key_t);
845       t = va_arg (arg, pth_time_t);
846       ev->u_type = PTH_EVENT_TIME;
847       ev->u.tv.tv_sec =  t.tv_sec;
848       ev->u.tv.tv_usec = t.tv_usec;
849     }
850   else if (spec & PTH_EVENT_MUTEX)
851     {
852       va_arg (arg, pth_key_t);
853       ev->u_type = PTH_EVENT_MUTEX;
854       ev->u.mx = va_arg (arg, pth_mutex_t*);
855     }
856     
857   memset (&sa, 0, sizeof sa);
858   sa.bInheritHandle = TRUE;
859   sa.lpSecurityDescriptor = NULL;
860   sa.nLength = sizeof sa;
861   ev->hd = CreateEvent (&sa, FALSE, FALSE, NULL);
862   if (!ev->hd)
863     {
864       free (ev);
865       return NULL;
866     }
867
868   return ev;
869 }
870
871 static pth_event_t
872 do_pth_event (unsigned long spec, ...)
873 {
874   va_list arg;
875   pth_event_t ev;
876
877   va_start (arg, spec);
878   ev = do_pth_event_body (spec, arg);
879   va_end (arg);
880     
881   return ev;
882 }
883
884 pth_event_t
885 pth_event (unsigned long spec, ...)
886 {
887   va_list arg;
888   pth_event_t ev;
889
890   implicit_init ();
891   enter_pth (__FUNCTION__);
892   
893   va_start (arg, spec);
894   ev = do_pth_event_body (spec, arg);
895   va_end (arg);
896     
897   leave_pth (__FUNCTION__);
898   return ev;
899 }
900
901
902 static void
903 pth_event_add (pth_event_t root, pth_event_t node)
904 {
905   pth_event_t n;
906
907   for (n=root; n->next; n = n->next)
908     ;
909   n->next = node;
910 }
911
912
913 pth_event_t
914 pth_event_concat (pth_event_t evf, ...)
915 {
916   pth_event_t evn;
917   va_list ap;
918
919   if (!evf)
920     return NULL;
921
922   implicit_init ();
923
924   va_start (ap, evf);
925   while ((evn = va_arg(ap, pth_event_t)) != NULL)
926     pth_event_add (evf, evn);
927   va_end (ap);
928
929   return evf;
930 }
931
932
933 static int
934 wait_for_fd (int fd, int is_read, int nwait)
935 {
936   struct timeval tv;
937   fd_set r;
938   fd_set w;
939   int n;
940
941   FD_ZERO (&r);
942   FD_ZERO (&w);    
943   FD_SET (fd, is_read ? &r : &w);
944
945   tv.tv_sec = nwait;
946   tv.tv_usec = 0;
947
948   while (1)
949     {
950       n = select (fd+1, &r, &w, NULL, &tv);
951       fprintf (stderr, "%s: wait_for_fd=%d fd %d (ec=%d)\n",
952                log_get_prefix (NULL), n, fd,(int)WSAGetLastError ());
953       if (n == -1)
954         break;
955       if (!n)
956         continue;
957       if (n == 1)
958         {
959           if (is_read && FD_ISSET (fd, &r))
960             break;
961           else if (FD_ISSET (fd, &w))
962             break;
963         }
964     }
965   return 0;
966 }
967
968
969 static void *
970 launch_thread (void *arg)
971 {
972   struct thread_info_s *c = arg;
973
974   if (c)
975     {
976       leave_pth (__FUNCTION__);
977       c->thread (c->arg);
978       if (!c->joinable && c->th)
979         {
980           CloseHandle (c->th);
981           c->th = NULL;
982         }
983       /* FIXME: We would badly fail if someone accesses the now
984          deallocated handle. Don't use it directly but setup proper
985          scheduling queues.  */
986       enter_pth (__FUNCTION__);
987       free (c);
988     }
989   ExitThread (0);
990   return NULL;
991 }
992
993 /* void */
994 /* sigemptyset (struct sigset_s * ss) */
995 /* { */
996 /*     if (ss) { */
997 /*      memset (ss->sigs, 0, sizeof ss->sigs); */
998 /*      ss->idx = 0; */
999 /*     } */
1000 /* } */
1001
1002
1003 /* int */
1004 /* sigaddset (struct sigset_s * ss, int signo) */
1005 /* { */
1006 /*     if (!ss) */
1007 /*      return -1; */
1008 /*     if (ss->idx + 1 > 64) */
1009 /*      return -1; */
1010 /*     ss->sigs[ss->idx] = signo; */
1011 /*     ss->idx++; */
1012 /*     return 0; */
1013 /* }  */
1014
1015
1016 static int
1017 sigpresent (struct sigset_s * ss, int signo)
1018 {
1019 /*     int i; */
1020 /*     for (i=0; i < ss->idx; i++) { */
1021 /*      if (ss->sigs[i] == signo) */
1022 /*          return 1; */
1023 /*     } */
1024 /* FIXME: See how to implement it.  */
1025     return 0;
1026 }
1027
1028
1029 static int
1030 do_pth_event_occurred (pth_event_t ev)
1031 {
1032   int ret;
1033
1034   if (!ev)
1035     return 0;
1036
1037   ret = 0;
1038   switch (ev->u_type)
1039     {
1040     case 0:
1041       if (WaitForSingleObject (ev->hd, 0) == WAIT_OBJECT_0)
1042         ret = 1;
1043       break;
1044
1045     case PTH_EVENT_SIGS:
1046       if (sigpresent (ev->u.sig, pth_signo) &&
1047           WaitForSingleObject (pth_signo_ev, 0) == WAIT_OBJECT_0)
1048         {
1049           fprintf (stderr, "%s: pth_event_occurred: sig signaled.\n",
1050                    log_get_prefix (NULL));
1051           (*ev->val) = pth_signo;
1052           ret = 1;
1053         }
1054       break;
1055
1056     case PTH_EVENT_FD:
1057       if (WaitForSingleObject (ev->hd, 0) == WAIT_OBJECT_0)
1058         ret = 1;
1059       break;
1060     }
1061
1062   return ret;
1063 }
1064
1065
1066 int
1067 pth_event_occurred (pth_event_t ev)
1068 {
1069   int ret;
1070
1071   implicit_init ();
1072   enter_pth (__FUNCTION__);
1073   ret = do_pth_event_occurred (ev);
1074   leave_pth (__FUNCTION__);
1075   return ret;
1076 }
1077
1078
1079 static int
1080 do_pth_event_status (pth_event_t ev)
1081 {
1082   if (!ev)
1083     return 0;
1084   if (do_pth_event_occurred (ev))
1085     return PTH_STATUS_OCCURRED;
1086   return 0;
1087 }
1088
1089 int
1090 pth_event_status (pth_event_t ev)
1091 {
1092   if (!ev)
1093     return 0;
1094   if (pth_event_occurred (ev))
1095     return PTH_STATUS_OCCURRED;
1096   return 0;
1097 }
1098
1099
1100 static int
1101 do_pth_event_free (pth_event_t ev, int mode)
1102 {
1103   pth_event_t n;
1104
1105   if (mode == PTH_FREE_ALL)
1106     {
1107       while (ev)
1108         {
1109           n = ev->next;
1110           CloseHandle (ev->hd);
1111           ev->hd = NULL;
1112           free (ev);
1113           ev = n;
1114         }
1115     }
1116   else if (mode == PTH_FREE_THIS)
1117     {
1118       ev->prev->next = ev->next;
1119       ev->next->prev = ev->prev;
1120       CloseHandle (ev->hd);
1121       ev->hd = NULL;        
1122       free (ev);
1123     }
1124
1125   return TRUE;
1126 }
1127
1128 int
1129 pth_event_free (pth_event_t ev, int mode)
1130 {
1131   int rc;
1132
1133   implicit_init ();
1134   enter_pth (__FUNCTION__);
1135   rc = do_pth_event_free (ev, mode);
1136   leave_pth (__FUNCTION__);
1137   return rc;
1138 }
1139
1140
1141 pth_event_t
1142 pth_event_isolate (pth_event_t ev)
1143 {
1144   pth_event_t ring = NULL;
1145
1146   if (!ev)
1147     return NULL;
1148   return ring;    
1149 }
1150
1151
1152 static int
1153 _pth_event_count (pth_event_t ev)
1154 {
1155   pth_event_t p;
1156   int cnt=0;
1157
1158   if (!ev)
1159     return 0;
1160   for (p = ev; p; p = p->next)
1161     cnt++;    
1162   return cnt;
1163 }
1164
1165
1166
1167 static pth_t
1168 spawn_helper_thread (void *(*func)(void *), void *arg)
1169 {
1170   SECURITY_ATTRIBUTES sa;
1171   DWORD tid;
1172   HANDLE th;
1173
1174   memset (&sa, 0, sizeof sa);
1175   sa.bInheritHandle = TRUE;
1176   sa.lpSecurityDescriptor = NULL;
1177   sa.nLength = sizeof sa;
1178
1179   fprintf (stderr, "%s: spawn_helper_thread creating thread ...\n",
1180            log_get_prefix (NULL));
1181   th = CreateThread (&sa, 32*1024,
1182                      (LPTHREAD_START_ROUTINE)func,
1183                      arg, 0, &tid);
1184   fprintf (stderr, "%s: spawn_helper_thread created thread %p\n",
1185            log_get_prefix (NULL), th);
1186
1187   return th;
1188 }
1189
1190
1191 static void 
1192 free_helper_threads (HANDLE *waitbuf, int *hdidx, int n)
1193 {
1194   int i;
1195
1196   for (i=0; i < n; i++)
1197     {
1198       CloseHandle (waitbuf[hdidx[i]]);
1199       waitbuf[hdidx[i]] = NULL;
1200     }
1201 }
1202
1203
1204 static void *
1205 wait_fd_thread (void * ctx)
1206 {
1207   pth_event_t ev = ctx;
1208
1209   wait_for_fd (ev->u.fd, ev->flags & PTH_UNTIL_FD_READABLE, 3600);
1210   fprintf (stderr, "%s: wait_fd_thread: exit.\n", log_get_prefix (NULL));
1211   SetEvent (ev->hd);
1212   ExitThread (0);
1213   return NULL;
1214 }
1215
1216
1217 static void *
1218 wait_timer_thread (void * ctx)
1219 {
1220   pth_event_t ev = ctx;
1221   int n = ev->u.tv.tv_sec*1000;
1222   Sleep (n);
1223   SetEvent (ev->hd);
1224   fprintf (stderr, "%s: wait_timer_thread: exit.\n", log_get_prefix (NULL));
1225   ExitThread (0);
1226   return NULL;
1227 }
1228
1229
1230 static int
1231 do_pth_wait (pth_event_t ev)
1232 {
1233   HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS/2];
1234   int    hdidx[MAXIMUM_WAIT_OBJECTS/2];
1235   DWORD n = 0;
1236   pth_event_t tmp;
1237   int pos=0, i=0;
1238
1239   if (!ev)
1240     return 0;
1241
1242   n =_pth_event_count (ev);
1243   if (n > MAXIMUM_WAIT_OBJECTS/2)
1244     return -1;
1245
1246   fprintf (stderr, "%s: pth_wait: cnt %lu\n", log_get_prefix (NULL), n);
1247   for (tmp = ev; tmp; tmp = tmp->next)
1248     {
1249       switch (tmp->u_type)
1250         {
1251         case 0:
1252           waitbuf[pos++] = tmp->hd;
1253           break;
1254
1255         case PTH_EVENT_SIGS:
1256           waitbuf[pos++] = pth_signo_ev;
1257           fprintf (stderr, "pth_wait: add signal event.\n");
1258           break;
1259
1260         case PTH_EVENT_FD:
1261           fprintf (stderr, "pth_wait: spawn event wait thread.\n");
1262           hdidx[i++] = pos;
1263           waitbuf[pos++] = spawn_helper_thread (wait_fd_thread, tmp);
1264           break;
1265
1266         case PTH_EVENT_TIME:
1267           fprintf (stderr, "pth_wait: spawn event timer thread.\n");
1268           hdidx[i++] = pos;
1269           waitbuf[pos++] = spawn_helper_thread (wait_timer_thread, tmp);
1270           break;
1271
1272         case PTH_EVENT_MUTEX:
1273           fprintf (stderr, "pth_wait: add mutex event.\n");
1274           hdidx[i++] = pos;
1275           waitbuf[pos++] = tmp->u.mx->mx;
1276           /* XXX: Use SetEvent(hd->ev) */
1277           break;
1278         }
1279     }
1280   fprintf (stderr, "%s: pth_wait: set %d\n", log_get_prefix (NULL), pos);
1281   n = WaitForMultipleObjects (pos, waitbuf, FALSE, INFINITE);
1282   free_helper_threads (waitbuf, hdidx, i);
1283   fprintf (stderr, "%s: pth_wait: n %ld\n", log_get_prefix (NULL), n);
1284
1285   if (n != WAIT_TIMEOUT)
1286     return 1;
1287     
1288   return 0;
1289 }
1290
1291 int
1292 pth_wait (pth_event_t ev)
1293 {
1294   int rc;
1295
1296   implicit_init ();
1297   enter_pth (__FUNCTION__);
1298   rc = do_pth_wait (ev);
1299   leave_pth (__FUNCTION__);
1300   return rc;
1301 }
1302
1303
1304 int
1305 pth_sleep (int sec)
1306 {
1307   static pth_key_t ev_key = PTH_KEY_INIT;
1308   pth_event_t ev;
1309
1310   implicit_init ();
1311   enter_pth (__FUNCTION__);
1312
1313   if (sec == 0)
1314     {
1315       leave_pth (__FUNCTION__);
1316       return 0;
1317     }
1318
1319   ev = do_pth_event (PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key,
1320                      pth_timeout (sec, 0));
1321   if (ev == NULL)
1322     {
1323       leave_pth (__FUNCTION__);
1324       return -1;
1325     }
1326   do_pth_wait (ev);
1327   do_pth_event_free (ev, PTH_FREE_ALL);
1328
1329   leave_pth (__FUNCTION__);
1330   return 0;
1331 }
1332
1333
1334
1335
1336 \f
1337 /* 
1338    Some simple tests.  
1339  */
1340 #ifdef TEST
1341 #include <stdio.h>
1342
1343 void * thread (void * c)
1344 {
1345
1346   Sleep (2000);
1347   SetEvent (((pth_event_t)c)->hd);
1348   fprintf (stderr, "\n\nhallo!.\n");
1349   pth_exit (NULL);
1350   return NULL;
1351 }
1352
1353
1354 int main_1 (int argc, char ** argv)
1355 {
1356   pth_attr_t t;
1357   pth_t hd;
1358   pth_event_t ev;
1359
1360   pth_init ();
1361   ev = pth_event (0, NULL);
1362   t = pth_attr_new ();
1363   pth_attr_set (t, PTH_ATTR_JOINABLE, 1);
1364   pth_attr_set (t, PTH_ATTR_STACK_SIZE, 4096);
1365   pth_attr_set (t, PTH_ATTR_NAME, "hello");
1366   hd = pth_spawn (t, thread, ev);
1367
1368   pth_wait (ev);
1369   pth_attr_destroy (t);
1370   pth_event_free (ev, 0);
1371   pth_kill ();
1372
1373   return 0;
1374 }
1375
1376
1377 static pth_event_t 
1378 setup_signals (struct sigset_s *sigs, int *signo)
1379 {
1380   pth_event_t ev;
1381
1382   sigemptyset (sigs);
1383   sigaddset (sigs, SIGINT);
1384   sigaddset (sigs, SIGTERM);
1385
1386   ev = pth_event (PTH_EVENT_SIGS, sigs, signo);
1387   return ev;
1388 }
1389
1390 int
1391 main_2 (int argc, char ** argv)
1392 {
1393   pth_event_t ev;
1394   struct sigset_s sigs;
1395   int signo = 0;
1396
1397   pth_init ();
1398   ev = setup_signals (&sigs, &signo);
1399   pth_wait (ev);
1400   if (pth_event_occured (ev) && signo)
1401     fprintf (stderr, "signal caught! signo %d\n", signo);
1402
1403   pth_event_free (ev, PTH_FREE_ALL);
1404   pth_kill ();
1405   return 0;
1406 }
1407
1408 int
1409 main_3 (int argc, char ** argv)
1410 {
1411   struct sockaddr_in addr, rem;
1412   int fd, n = 0, infd;
1413   int signo = 0;
1414   struct sigset_s sigs;
1415   pth_event_t ev;
1416
1417   pth_init ();
1418   fd = socket (AF_INET, SOCK_STREAM, 0);
1419
1420   memset (&addr, 0, sizeof addr);
1421   addr.sin_addr.s_addr = INADDR_ANY;
1422   addr.sin_port = htons (5050);
1423   addr.sin_family = AF_INET;
1424   bind (fd, (struct sockaddr*)&addr, sizeof addr);
1425   listen (fd, 5);
1426
1427   ev = setup_signals (&sigs, &signo);
1428   n = sizeof addr;
1429   infd = pth_accept_ev (fd, (struct sockaddr *)&rem, &n, ev);
1430   fprintf (stderr, "infd %d: %s:%d\n", infd, inet_ntoa (rem.sin_addr),
1431           htons (rem.sin_port));
1432
1433   closesocket (infd);
1434   pth_event_free (ev, PTH_FREE_ALL);
1435   pth_kill ();
1436   return 0;
1437 }
1438
1439 int
1440 main (int argc, char ** argv)
1441 {
1442   pth_event_t ev;
1443   pth_key_t ev_key;
1444
1445   pth_init ();
1446   /*ev = pth_event (PTH_EVENT_TIME, &ev_key, pth_timeout (5, 0));
1447     pth_wait (ev);
1448     pth_event_free (ev, PTH_FREE_ALL);*/
1449   pth_sleep (5);
1450   pth_kill ();
1451   return 0;
1452 }
1453 #endif
1454
1455 #endif /*HAVE_W32_SYSTEM*/
1456