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