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