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