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