2006-07-29 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / jnlib / w32-pth.c
blob4107c7cb325e234aa42d6516d2a2af5fd01261e2
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
5 * This file is part of GnuPG.
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.
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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
22 * ------------------------------------------------------------------
23 * This code is based on Ralf Engelschall's GNU Pth, a non-preemptive
24 * thread scheduling library which can be found at
25 * http://www.gnu.org/software/pth/. MS Windows (W32) specific code
26 * written by Timo Schulz, g10 Code.
29 #include <config.h>
30 #ifdef HAVE_W32_SYSTEM
31 #include <windows.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <io.h>
35 #include <signal.h>
37 #include "logging.h" /* For log_get_prefix () */
39 /* We don't want to have any Windows specific code in the header, thus
40 we use a macro which defaults to a compatible type in w32-pth.h. */
41 #define W32_PTH_HANDLE_INTERNAL HANDLE
42 #include "w32-pth.h"
45 #ifndef FALSE
46 #define FALSE 0
47 #endif
48 #ifndef TRUE
49 #define TRUE 1
50 #endif
51 #if FALSE != 0 || TRUE != 1
52 #error TRUE or FALSE defined to wrong values
53 #endif
56 /* States whether this module has been initialized. */
57 static int pth_initialized;
59 /* Keeps the current debug level. Define marcos to test them. */
60 static int debug_level;
61 #define DBG_ERROR (debug_level >= 1)
62 #define DBG_INFO (debug_level >= 2)
63 #define DBG_CALLS (debug_level >= 3)
65 /* Variables to support event handling. */
66 static int pth_signo;
67 static HANDLE pth_signo_ev;
69 /* Mutex to make sure only one thread is running. */
70 static CRITICAL_SECTION pth_shd;
72 /* Events are store in a double linked event ring. */
73 struct pth_event_s
75 struct pth_event_s * next;
76 struct pth_event_s * prev;
77 HANDLE hd;
78 union
80 struct sigset_s * sig;
81 int fd;
82 struct timeval tv;
83 pth_mutex_t * mx;
84 } u;
85 int * val;
86 int u_type;
87 int flags;
91 struct pth_attr_s
93 unsigned int flags;
94 unsigned int stack_size;
95 char * name;
99 /* Object to keep information about a thread. This may eventually be
100 used to implement a scheduler queue. */
101 struct thread_info_s
103 void *(*thread)(void *); /* The actual thread fucntion. */
104 void * arg; /* The argument passed to that fucntion. */
105 int joinable; /* True if this Thread is joinable. */
106 HANDLE th; /* Handle of this thread. Used by non-joinable
107 threads to close the handle. */
111 /* Convenience macro to startup the system. */
112 #define implicit_init() do { if (!pth_initialized) pth_init(); } while (0)
114 /* Prototypes. */
115 static pth_event_t do_pth_event (unsigned long spec, ...);
116 static unsigned int do_pth_waitpid (unsigned pid, int * status, int options);
117 static int do_pth_wait (pth_event_t ev);
118 static int do_pth_event_status (pth_event_t ev);
119 static void *launch_thread (void * ctx);
125 pth_init (void)
127 SECURITY_ATTRIBUTES sa;
128 WSADATA wsadat;
129 const char *s;
131 if (pth_initialized)
132 return TRUE;
134 debug_level = (s=getenv ("DEBUG_PTH"))? atoi (s):0;
135 if (debug_level)
136 fprintf (stderr, "%s: pth_init: called.\n", log_get_prefix (NULL));
138 if (WSAStartup (0x202, &wsadat))
139 return FALSE;
140 pth_signo = 0;
141 InitializeCriticalSection (&pth_shd);
142 if (pth_signo_ev)
143 CloseHandle (pth_signo_ev);
144 memset (&sa, 0, sizeof sa);
145 sa.bInheritHandle = TRUE;
146 sa.lpSecurityDescriptor = NULL;
147 sa.nLength = sizeof sa;
148 pth_signo_ev = CreateEvent (&sa, TRUE, FALSE, NULL);
149 if (!pth_signo_ev)
150 return FALSE;
152 pth_initialized = 1;
153 EnterCriticalSection (&pth_shd);
154 return TRUE;
159 pth_kill (void)
161 pth_signo = 0;
162 if (pth_signo_ev)
164 CloseHandle (pth_signo_ev);
165 pth_signo_ev = NULL;
167 if (pth_initialized)
168 DeleteCriticalSection (&pth_shd);
169 WSACleanup ();
170 pth_initialized = 0;
171 return TRUE;
175 static char *
176 w32_strerror (char *strerr, size_t strerrsize)
178 if (strerrsize > 1)
179 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, (int)GetLastError (),
180 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
181 strerr, strerrsize, NULL);
182 return strerr;
186 static void
187 enter_pth (const char *function)
189 /* Fixme: I am not sure whether the same thread my enter a critical
190 section twice. */
191 if (DBG_CALLS)
192 fprintf (stderr, "%s: enter_pth (%s)\n",
193 log_get_prefix (NULL), function? function:"");
194 LeaveCriticalSection (&pth_shd);
198 static void
199 leave_pth (const char *function)
201 EnterCriticalSection (&pth_shd);
202 if (DBG_CALLS)
203 fprintf (stderr, "%s: leave_pth (%s)\n",
204 log_get_prefix (NULL), function? function:"");
208 long
209 pth_ctrl (unsigned long query, ...)
211 implicit_init ();
213 switch (query)
215 case PTH_CTRL_GETAVLOAD:
216 case PTH_CTRL_GETPRIO:
217 case PTH_CTRL_GETNAME:
218 case PTH_CTRL_GETTHREADS_NEW:
219 case PTH_CTRL_GETTHREADS_READY:
220 case PTH_CTRL_GETTHREADS_RUNNING:
221 case PTH_CTRL_GETTHREADS_WAITING:
222 case PTH_CTRL_GETTHREADS_SUSPENDED:
223 case PTH_CTRL_GETTHREADS_DEAD:
224 case PTH_CTRL_GETTHREADS:
225 default:
226 return -1;
228 return 0;
233 pth_time_t
234 pth_timeout (long sec, long usec)
236 pth_time_t tvd;
238 tvd.tv_sec = sec;
239 tvd.tv_usec = usec;
240 return tvd;
245 pth_read_ev (int fd, void *buffer, size_t size, pth_event_t ev)
247 implicit_init ();
248 return 0;
253 pth_read (int fd, void * buffer, size_t size)
255 int n;
257 implicit_init ();
258 enter_pth (__FUNCTION__);
260 n = recv (fd, buffer, size, 0);
261 if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
263 DWORD nread = 0;
264 n = ReadFile ((HANDLE)fd, buffer, size, &nread, NULL);
265 if (!n)
267 char strerr[256];
269 if (DBG_ERROR)
270 fprintf (stderr, "%s: pth_read(%d) failed read from file: %s\n",
271 log_get_prefix (NULL), fd,
272 w32_strerror (strerr, sizeof strerr));
273 n = -1;
275 else
276 n = (int)nread;
278 leave_pth (__FUNCTION__);
279 return n;
284 pth_write_ev (int fd, const void *buffer, size_t size, pth_event_t ev)
286 implicit_init ();
287 return 0;
292 pth_write (int fd, const void * buffer, size_t size)
294 int n;
296 implicit_init ();
297 enter_pth (__FUNCTION__);
298 n = send (fd, buffer, size, 0);
299 if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
301 DWORD nwrite;
302 char strerr[256];
304 /* This is no real error because we first need to figure out if
305 we have a handle or a socket. */
307 n = WriteFile ((HANDLE)fd, buffer, size, &nwrite, NULL);
308 if (!n)
310 if (DBG_ERROR)
311 fprintf (stderr, "%s: pth_write(%d) failed in write: %s\n",
312 log_get_prefix (NULL), fd,
313 w32_strerror (strerr, sizeof strerr));
314 n = -1;
316 else
317 n = (int)nwrite;
319 leave_pth (__FUNCTION__);
320 return n;
325 pth_select (int nfds, fd_set * rfds, fd_set * wfds, fd_set * efds,
326 const struct timeval * timeout)
328 int n;
330 implicit_init ();
331 enter_pth (__FUNCTION__);
332 n = select (nfds, rfds, wfds, efds, timeout);
333 leave_pth (__FUNCTION__);
334 return n;
339 pth_fdmode (int fd, int mode)
341 unsigned long val;
342 int ret = PTH_FDMODE_BLOCK;
344 implicit_init ();
345 /* Note: we don't do the eter/leave pth here because this is for one
346 a fast fucntion and secondly already called from inside such a
347 block. */
348 /* XXX: figure out original fd mode */
349 switch (mode)
351 case PTH_FDMODE_NONBLOCK:
352 val = 1;
353 if (ioctlsocket (fd, FIONBIO, &val) == SOCKET_ERROR)
354 ret = PTH_FDMODE_ERROR;
355 break;
357 case PTH_FDMODE_BLOCK:
358 val = 0;
359 if (ioctlsocket (fd, FIONBIO, &val) == SOCKET_ERROR)
360 ret = PTH_FDMODE_ERROR;
361 break;
363 return ret;
368 pth_accept (int fd, struct sockaddr *addr, int *addrlen)
370 int rc;
372 implicit_init ();
373 enter_pth (__FUNCTION__);
374 rc = accept (fd, addr, addrlen);
375 leave_pth (__FUNCTION__);
376 return rc;
381 pth_accept_ev (int fd, struct sockaddr *addr, int *addrlen,
382 pth_event_t ev_extra)
384 pth_key_t ev_key;
385 pth_event_t ev;
386 int rv;
387 int fdmode;
389 implicit_init ();
390 enter_pth (__FUNCTION__);
392 fdmode = pth_fdmode (fd, PTH_FDMODE_NONBLOCK);
393 if (fdmode == PTH_FDMODE_ERROR)
395 leave_pth (__FUNCTION__);
396 return -1;
399 ev = NULL;
400 while ((rv = accept (fd, addr, addrlen)) == -1 &&
401 (WSAGetLastError () == WSAEINPROGRESS ||
402 WSAGetLastError () == WSAEWOULDBLOCK))
404 if (!ev)
406 ev = do_pth_event (PTH_EVENT_FD|PTH_UNTIL_FD_READABLE|
407 PTH_MODE_STATIC, &ev_key, fd);
408 if (!ev)
410 leave_pth (__FUNCTION__);
411 return -1;
413 if (ev_extra)
414 pth_event_concat (ev, ev_extra, NULL);
416 /* Wait until accept has a chance. */
417 do_pth_wait (ev);
418 if (ev_extra)
420 pth_event_isolate (ev);
421 if (do_pth_event_status (ev) != PTH_STATUS_OCCURRED)
423 pth_fdmode (fd, fdmode);
424 leave_pth (__FUNCTION__);
425 return -1;
430 pth_fdmode (fd, fdmode);
431 leave_pth (__FUNCTION__);
432 return rv;
437 pth_connect (int fd, struct sockaddr *name, int namelen)
439 int rc;
441 implicit_init ();
442 enter_pth (__FUNCTION__);
443 rc = connect (fd, name, namelen);
444 leave_pth (__FUNCTION__);
445 return rc;
450 pth_mutex_release (pth_mutex_t *mutex)
452 int rc;
454 implicit_init ();
455 enter_pth (__FUNCTION__);
457 if (!ReleaseMutex (*mutex))
459 char strerr[256];
461 if (DBG_ERROR)
462 fprintf (stderr, "%s: pth_release_mutex %p failed: %s\n",
463 log_get_prefix (NULL), *mutex,
464 w32_strerror (strerr, sizeof strerr));
465 rc = FALSE;
467 else
468 rc = TRUE;
470 leave_pth (__FUNCTION__);
471 return rc;
476 pth_mutex_acquire (pth_mutex_t *mutex, int tryonly, pth_event_t ev_extra)
478 int code;
479 int rc;
481 implicit_init ();
482 enter_pth (__FUNCTION__);
484 /* FIXME: ev_extra is not yet supported. */
486 code = WaitForSingleObject (*mutex, INFINITE);
487 switch (code)
489 case WAIT_FAILED:
491 char strerr[256];
493 if (DBG_ERROR)
494 fprintf (stderr, "%s: pth_mutex_acquire for %p failed: %s\n",
495 log_get_prefix (NULL), *mutex,
496 w32_strerror (strerr, sizeof strerr));
498 rc = FALSE;
499 break;
501 case WAIT_OBJECT_0:
502 rc = TRUE;
503 break;
505 default:
506 if (DBG_ERROR)
507 fprintf (stderr, "%s: WaitForSingleObject returned unexpected "
508 "code %d for mutex %p\n",
509 log_get_prefix (NULL), code, *mutex);
510 rc = FALSE;
511 break;
514 leave_pth (__FUNCTION__);
515 return rc;
521 pth_mutex_init (pth_mutex_t *mutex)
523 SECURITY_ATTRIBUTES sa;
525 implicit_init ();
526 enter_pth (__FUNCTION__);
528 memset (&sa, 0, sizeof sa);
529 sa.bInheritHandle = TRUE;
530 sa.lpSecurityDescriptor = NULL;
531 sa.nLength = sizeof sa;
532 *mutex = CreateMutex (&sa, FALSE, NULL);
533 if (!*mutex)
535 free (*mutex);
536 *mutex = NULL;
537 leave_pth (__FUNCTION__);
538 return FALSE;
541 leave_pth (__FUNCTION__);
542 return TRUE;
546 pth_attr_t
547 pth_attr_new (void)
549 pth_attr_t hd;
551 implicit_init ();
552 hd = calloc (1, sizeof *hd);
553 return hd;
558 pth_attr_destroy (pth_attr_t hd)
560 if (!hd)
561 return -1;
562 implicit_init ();
563 if (hd->name)
564 free (hd->name);
565 free (hd);
566 return TRUE;
571 pth_attr_set (pth_attr_t hd, int field, ...)
573 va_list args;
574 char * str;
575 int val;
576 int rc = TRUE;
578 implicit_init ();
580 va_start (args, field);
581 switch (field)
583 case PTH_ATTR_JOINABLE:
584 val = va_arg (args, int);
585 if (val)
587 hd->flags |= PTH_ATTR_JOINABLE;
588 if (DBG_INFO)
589 fprintf (stderr, "%s: pth_attr_set: PTH_ATTR_JOINABLE\n",
590 log_get_prefix (NULL));
592 break;
594 case PTH_ATTR_STACK_SIZE:
595 val = va_arg (args, int);
596 if (val)
598 hd->flags |= PTH_ATTR_STACK_SIZE;
599 hd->stack_size = val;
600 if (DBG_INFO)
601 fprintf (stderr, "%s: pth_attr_set: PTH_ATTR_STACK_SIZE %d\n",
602 log_get_prefix (NULL), val);
604 break;
606 case PTH_ATTR_NAME:
607 str = va_arg (args, char*);
608 if (hd->name)
609 free (hd->name);
610 if (str)
612 hd->name = strdup (str);
613 if (!hd->name)
614 return FALSE;
615 hd->flags |= PTH_ATTR_NAME;
616 if (DBG_INFO)
617 fprintf (stderr, "%s: pth_attr_set: PTH_ATTR_NAME %s\n",
618 log_get_prefix (NULL), hd->name);
620 break;
622 default:
623 rc = FALSE;
624 break;
626 va_end (args);
627 return rc;
631 static pth_t
632 do_pth_spawn (pth_attr_t hd, void *(*func)(void *), void *arg)
634 SECURITY_ATTRIBUTES sa;
635 DWORD tid;
636 HANDLE th;
637 struct thread_info_s *ctx;
639 if (!hd)
640 return NULL;
642 memset (&sa, 0, sizeof sa);
643 sa.bInheritHandle = TRUE;
644 sa.lpSecurityDescriptor = NULL;
645 sa.nLength = sizeof sa;
647 ctx = calloc (1, sizeof *ctx);
648 if (!ctx)
649 return NULL;
650 ctx->thread = func;
651 ctx->arg = arg;
652 ctx->joinable = (hd->flags & PTH_ATTR_JOINABLE);
654 /* XXX: we don't use all thread attributes. */
656 /* Note that we create the thread suspended so that we are able to
657 store the thread's handle in the context structure. We need to
658 do this to be able to close the handle from the launch helper.
660 FIXME: We should no use th W32's Thread handle directly but keep
661 our own thread control structure. CTX may be used for that. */
662 if (DBG_INFO)
663 fprintf (stderr, "%s: do_pth_spawn creating thread ...\n",
664 log_get_prefix (NULL));
665 th = CreateThread (&sa, hd->stack_size,
666 (LPTHREAD_START_ROUTINE)launch_thread,
667 ctx, CREATE_SUSPENDED, &tid);
668 ctx->th = th;
669 if (DBG_INFO)
670 fprintf (stderr, "%s: do_pth_spawn created thread %p\n",
671 log_get_prefix (NULL),th);
672 if (!th)
673 free (ctx);
674 else
675 ResumeThread (th);
677 return th;
680 pth_t
681 pth_spawn (pth_attr_t hd, void *(*func)(void *), void *arg)
683 HANDLE th;
685 if (!hd)
686 return NULL;
688 implicit_init ();
689 enter_pth (__FUNCTION__);
690 th = do_pth_spawn (hd, func, arg);
691 leave_pth (__FUNCTION__);
692 return th;
696 pth_t
697 pth_self (void)
699 return GetCurrentThread ();
703 pth_join (pth_t hd, void **value)
705 return TRUE;
709 /* friendly */
711 pth_cancel (pth_t hd)
713 if (!hd)
714 return -1;
715 implicit_init ();
716 enter_pth (__FUNCTION__);
717 WaitForSingleObject (hd, 1000);
718 TerminateThread (hd, 0);
719 leave_pth (__FUNCTION__);
720 return TRUE;
724 /* cruel */
726 pth_abort (pth_t hd)
728 if (!hd)
729 return -1;
730 implicit_init ();
731 enter_pth (__FUNCTION__);
732 TerminateThread (hd, 0);
733 leave_pth (__FUNCTION__);
734 return TRUE;
738 void
739 pth_exit (void *value)
741 implicit_init ();
742 enter_pth (__FUNCTION__);
743 pth_kill ();
744 leave_pth (__FUNCTION__);
745 exit ((int)(long)value);
749 static unsigned int
750 do_pth_waitpid (unsigned pid, int * status, int options)
752 #if 0
753 pth_event_t ev;
754 static pth_key_t ev_key = PTH_KEY_INIT;
755 pid_t pid;
757 pth_debug2("pth_waitpid: called from thread \"%s\"", pth_current->name);
759 for (;;)
761 /* do a non-blocking poll for the pid */
762 while ( (pid = pth_sc(waitpid)(wpid, status, options|WNOHANG)) < 0
763 && errno == EINTR)
766 /* if pid was found or caller requested a polling return immediately */
767 if (pid == -1 || pid > 0 || (pid == 0 && (options & WNOHANG)))
768 break;
770 /* else wait a little bit */
771 ev = pth_event(PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key,
772 pth_timeout (0,250000));
773 pth_wait(ev);
776 pth_debug2("pth_waitpid: leave to thread \"%s\"", pth_current->name);
777 #endif
778 return 0;
782 unsigned int
783 pth_waitpid (unsigned pid, int * status, int options)
785 unsigned int n;
787 implicit_init ();
788 enter_pth (__FUNCTION__);
789 n = do_pth_waitpid (pid, status, options);
790 leave_pth (__FUNCTION__);
791 return n;
795 static BOOL WINAPI
796 sig_handler (DWORD signo)
798 switch (signo)
800 case CTRL_C_EVENT: pth_signo = SIGINT; break;
801 case CTRL_BREAK_EVENT: pth_signo = SIGTERM; break;
803 SetEvent (pth_signo_ev);
804 if (DBG_INFO)
805 fprintf (stderr, "%s: sig_handler=%d\n", log_get_prefix (NULL), pth_signo);
806 return TRUE;
810 static pth_event_t
811 do_pth_event_body (unsigned long spec, va_list arg)
813 SECURITY_ATTRIBUTES sa;
814 pth_event_t ev;
815 int rc;
817 if (DBG_INFO)
818 fprintf (stderr, "%s: pth_event spec=%lu\n", log_get_prefix (NULL), spec);
819 ev = calloc (1, sizeof *ev);
820 if (!ev)
821 return NULL;
822 if (spec == 0)
824 else if (spec & PTH_EVENT_SIGS)
826 ev->u.sig = va_arg (arg, struct sigset_s *);
827 ev->u_type = PTH_EVENT_SIGS;
828 ev->val = va_arg (arg, int *);
829 rc = SetConsoleCtrlHandler (sig_handler, TRUE);
830 if (DBG_INFO)
831 fprintf (stderr, "%s: pth_event: sigs rc=%d\n",
832 log_get_prefix (NULL), rc);
834 else if (spec & PTH_EVENT_FD)
836 if (spec & PTH_UNTIL_FD_READABLE)
837 ev->flags |= PTH_UNTIL_FD_READABLE;
838 if (spec & PTH_MODE_STATIC)
839 ev->flags |= PTH_MODE_STATIC;
840 ev->u_type = PTH_EVENT_FD;
841 va_arg (arg, pth_key_t);
842 ev->u.fd = va_arg (arg, int);
843 if (DBG_INFO)
844 fprintf (stderr, "%s: pth_event: fd=%d\n",
845 log_get_prefix (NULL), ev->u.fd);
847 else if (spec & PTH_EVENT_TIME)
849 pth_time_t t;
850 if (spec & PTH_MODE_STATIC)
851 ev->flags |= PTH_MODE_STATIC;
852 va_arg (arg, pth_key_t);
853 t = va_arg (arg, pth_time_t);
854 ev->u_type = PTH_EVENT_TIME;
855 ev->u.tv.tv_sec = t.tv_sec;
856 ev->u.tv.tv_usec = t.tv_usec;
858 else if (spec & PTH_EVENT_MUTEX)
860 va_arg (arg, pth_key_t);
861 ev->u_type = PTH_EVENT_MUTEX;
862 ev->u.mx = va_arg (arg, pth_mutex_t*);
865 memset (&sa, 0, sizeof sa);
866 sa.bInheritHandle = TRUE;
867 sa.lpSecurityDescriptor = NULL;
868 sa.nLength = sizeof sa;
869 ev->hd = CreateEvent (&sa, FALSE, FALSE, NULL);
870 if (!ev->hd)
872 free (ev);
873 return NULL;
875 ev->next = ev;
876 ev->prev = ev;
878 return ev;
881 static pth_event_t
882 do_pth_event (unsigned long spec, ...)
884 va_list arg;
885 pth_event_t ev;
887 va_start (arg, spec);
888 ev = do_pth_event_body (spec, arg);
889 va_end (arg);
891 return ev;
894 pth_event_t
895 pth_event (unsigned long spec, ...)
897 va_list arg;
898 pth_event_t ev;
900 implicit_init ();
901 enter_pth (__FUNCTION__);
903 va_start (arg, spec);
904 ev = do_pth_event_body (spec, arg);
905 va_end (arg);
907 leave_pth (__FUNCTION__);
908 return ev;
912 static void
913 pth_event_add (pth_event_t root, pth_event_t node)
915 pth_event_t n;
917 for (n=root; n->next; n = n->next)
919 n->next = node;
923 pth_event_t
924 pth_event_concat (pth_event_t evf, ...)
926 pth_event_t evn;
927 va_list ap;
929 if (!evf)
930 return NULL;
932 implicit_init ();
934 va_start (ap, evf);
935 while ((evn = va_arg(ap, pth_event_t)) != NULL)
936 pth_event_add (evf, evn);
937 va_end (ap);
939 return evf;
943 static int
944 wait_for_fd (int fd, int is_read, int nwait)
946 struct timeval tv;
947 fd_set r;
948 fd_set w;
949 int n;
951 FD_ZERO (&r);
952 FD_ZERO (&w);
953 FD_SET (fd, is_read ? &r : &w);
955 tv.tv_sec = nwait;
956 tv.tv_usec = 0;
958 while (1)
960 n = select (fd+1, &r, &w, NULL, &tv);
961 if (DBG_INFO)
962 fprintf (stderr, "%s: wait_for_fd=%d fd %d (ec=%d)\n",
963 log_get_prefix (NULL), n, fd,(int)WSAGetLastError ());
964 if (n == -1)
965 break;
966 if (!n)
967 continue;
968 if (n == 1)
970 if (is_read && FD_ISSET (fd, &r))
971 break;
972 else if (FD_ISSET (fd, &w))
973 break;
976 return 0;
980 static void *
981 launch_thread (void *arg)
983 struct thread_info_s *c = arg;
985 if (c)
987 leave_pth (__FUNCTION__);
988 c->thread (c->arg);
989 if (!c->joinable && c->th)
991 CloseHandle (c->th);
992 c->th = NULL;
994 /* FIXME: We would badly fail if someone accesses the now
995 deallocated handle. Don't use it directly but setup proper
996 scheduling queues. */
997 enter_pth (__FUNCTION__);
998 free (c);
1000 ExitThread (0);
1001 return NULL;
1004 /* void */
1005 /* sigemptyset (struct sigset_s * ss) */
1006 /* { */
1007 /* if (ss) { */
1008 /* memset (ss->sigs, 0, sizeof ss->sigs); */
1009 /* ss->idx = 0; */
1010 /* } */
1011 /* } */
1014 /* int */
1015 /* sigaddset (struct sigset_s * ss, int signo) */
1016 /* { */
1017 /* if (!ss) */
1018 /* return -1; */
1019 /* if (ss->idx + 1 > 64) */
1020 /* return -1; */
1021 /* ss->sigs[ss->idx] = signo; */
1022 /* ss->idx++; */
1023 /* return 0; */
1024 /* } */
1027 static int
1028 sigpresent (struct sigset_s * ss, int signo)
1030 /* int i; */
1031 /* for (i=0; i < ss->idx; i++) { */
1032 /* if (ss->sigs[i] == signo) */
1033 /* return 1; */
1034 /* } */
1035 /* FIXME: See how to implement it. */
1036 return 0;
1040 static int
1041 do_pth_event_occurred (pth_event_t ev)
1043 int ret;
1045 if (!ev)
1046 return 0;
1048 ret = 0;
1049 switch (ev->u_type)
1051 case 0:
1052 if (WaitForSingleObject (ev->hd, 0) == WAIT_OBJECT_0)
1053 ret = 1;
1054 break;
1056 case PTH_EVENT_SIGS:
1057 if (sigpresent (ev->u.sig, pth_signo) &&
1058 WaitForSingleObject (pth_signo_ev, 0) == WAIT_OBJECT_0)
1060 if (DBG_INFO)
1061 fprintf (stderr, "%s: pth_event_occurred: sig signaled.\n",
1062 log_get_prefix (NULL));
1063 (*ev->val) = pth_signo;
1064 ret = 1;
1066 break;
1068 case PTH_EVENT_FD:
1069 if (WaitForSingleObject (ev->hd, 0) == WAIT_OBJECT_0)
1070 ret = 1;
1071 break;
1074 return ret;
1079 pth_event_occurred (pth_event_t ev)
1081 int ret;
1083 implicit_init ();
1084 enter_pth (__FUNCTION__);
1085 ret = do_pth_event_occurred (ev);
1086 leave_pth (__FUNCTION__);
1087 return ret;
1091 static int
1092 do_pth_event_status (pth_event_t ev)
1094 if (!ev)
1095 return 0;
1096 if (do_pth_event_occurred (ev))
1097 return PTH_STATUS_OCCURRED;
1098 return 0;
1102 pth_event_status (pth_event_t ev)
1104 if (!ev)
1105 return 0;
1106 if (pth_event_occurred (ev))
1107 return PTH_STATUS_OCCURRED;
1108 return 0;
1112 static int
1113 do_pth_event_free (pth_event_t ev, int mode)
1115 if (!ev)
1116 return FALSE;
1118 if (mode == PTH_FREE_ALL)
1120 pth_event_t cur = ev;
1123 pth_event_t next = cur->next;
1124 CloseHandle (cur->hd);
1125 cur->hd = NULL;
1126 free (cur);
1127 cur = next;
1129 while (cur != ev);
1131 else if (mode == PTH_FREE_THIS)
1133 ev->prev->next = ev->next;
1134 ev->next->prev = ev->prev;
1135 CloseHandle (ev->hd);
1136 ev->hd = NULL;
1137 free (ev);
1139 else
1140 return FALSE;
1142 return TRUE;
1146 pth_event_free (pth_event_t ev, int mode)
1148 int rc;
1150 implicit_init ();
1151 enter_pth (__FUNCTION__);
1152 rc = do_pth_event_free (ev, mode);
1153 leave_pth (__FUNCTION__);
1154 return rc;
1158 pth_event_t
1159 pth_event_isolate (pth_event_t ev)
1161 pth_event_t ring;
1163 if (!ev)
1164 return NULL;
1165 if (ev->next == ev && ev->prev == ev)
1166 return NULL; /* Only one event. */
1168 ring = ev->next;
1169 ev->prev->next = ev->next;
1170 ev->next->prev = ev->prev;
1171 ev->prev = ev;
1172 ev->next = ev;
1173 return ring;
1177 static int
1178 event_count (pth_event_t ev)
1180 pth_event_t r;
1181 int cnt = 0;
1183 if (ev)
1185 r = ev;
1188 cnt++;
1189 r = r->next;
1191 while (r != ev);
1194 return cnt;
1199 static pth_t
1200 spawn_helper_thread (void *(*func)(void *), void *arg)
1202 SECURITY_ATTRIBUTES sa;
1203 DWORD tid;
1204 HANDLE th;
1206 memset (&sa, 0, sizeof sa);
1207 sa.bInheritHandle = TRUE;
1208 sa.lpSecurityDescriptor = NULL;
1209 sa.nLength = sizeof sa;
1211 if (DBG_INFO)
1212 fprintf (stderr, "%s: spawn_helper_thread creating thread ...\n",
1213 log_get_prefix (NULL));
1214 th = CreateThread (&sa, 32*1024,
1215 (LPTHREAD_START_ROUTINE)func,
1216 arg, 0, &tid);
1217 if (DBG_INFO)
1218 fprintf (stderr, "%s: spawn_helper_thread created thread %p\n",
1219 log_get_prefix (NULL), th);
1221 return th;
1225 static void
1226 free_helper_threads (HANDLE *waitbuf, int *hdidx, int n)
1228 int i;
1230 for (i=0; i < n; i++)
1232 CloseHandle (waitbuf[hdidx[i]]);
1233 waitbuf[hdidx[i]] = NULL;
1238 static void *
1239 wait_fd_thread (void * ctx)
1241 pth_event_t ev = ctx;
1243 wait_for_fd (ev->u.fd, ev->flags & PTH_UNTIL_FD_READABLE, 3600);
1244 if (DBG_INFO)
1245 fprintf (stderr, "%s: wait_fd_thread: exit.\n", log_get_prefix (NULL));
1246 SetEvent (ev->hd);
1247 ExitThread (0);
1248 return NULL;
1252 static void *
1253 wait_timer_thread (void * ctx)
1255 pth_event_t ev = ctx;
1256 int n = ev->u.tv.tv_sec*1000;
1257 Sleep (n);
1258 SetEvent (ev->hd);
1259 if (DBG_INFO)
1260 fprintf (stderr, "%s: wait_timer_thread: exit.\n", log_get_prefix (NULL));
1261 ExitThread (0);
1262 return NULL;
1266 static int
1267 do_pth_wait (pth_event_t ev)
1269 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS/2];
1270 int hdidx[MAXIMUM_WAIT_OBJECTS/2];
1271 DWORD n = 0;
1272 int pos=0, i=0;
1274 if (!ev)
1275 return 0;
1277 n = event_count (ev);
1278 if (n > MAXIMUM_WAIT_OBJECTS/2)
1279 return -1;
1281 if (DBG_INFO)
1282 fprintf (stderr, "%s: pth_wait: cnt %lu\n", log_get_prefix (NULL), n);
1283 if (ev)
1285 pth_event_t r = ev;
1288 switch (r->u_type)
1290 case 0:
1291 waitbuf[pos++] = r->hd;
1292 break;
1294 case PTH_EVENT_SIGS:
1295 waitbuf[pos++] = pth_signo_ev;
1296 if (DBG_INFO)
1297 fprintf (stderr, "pth_wait: add signal event.\n");
1298 break;
1300 case PTH_EVENT_FD:
1301 if (DBG_INFO)
1302 fprintf (stderr, "pth_wait: spawn event wait thread.\n");
1303 hdidx[i++] = pos;
1304 waitbuf[pos++] = spawn_helper_thread (wait_fd_thread, r);
1305 break;
1307 case PTH_EVENT_TIME:
1308 if (DBG_INFO)
1309 fprintf (stderr, "pth_wait: spawn event timer thread.\n");
1310 hdidx[i++] = pos;
1311 waitbuf[pos++] = spawn_helper_thread (wait_timer_thread, r);
1312 break;
1314 case PTH_EVENT_MUTEX:
1315 if (DBG_INFO)
1316 fprintf (stderr, "pth_wait: ignoring mutex event.\n");
1317 break;
1320 while ( r != ev );
1322 if (DBG_INFO)
1323 fprintf (stderr, "%s: pth_wait: set %d\n", log_get_prefix (NULL), pos);
1324 n = WaitForMultipleObjects (pos, waitbuf, FALSE, INFINITE);
1325 free_helper_threads (waitbuf, hdidx, i);
1326 if (DBG_INFO)
1327 fprintf (stderr, "%s: pth_wait: n %ld\n", log_get_prefix (NULL), n);
1329 if (n != WAIT_TIMEOUT)
1330 return 1;
1332 return 0;
1336 pth_wait (pth_event_t ev)
1338 int rc;
1340 implicit_init ();
1341 enter_pth (__FUNCTION__);
1342 rc = do_pth_wait (ev);
1343 leave_pth (__FUNCTION__);
1344 return rc;
1349 pth_sleep (int sec)
1351 static pth_key_t ev_key = PTH_KEY_INIT;
1352 pth_event_t ev;
1354 implicit_init ();
1355 enter_pth (__FUNCTION__);
1357 if (sec == 0)
1359 leave_pth (__FUNCTION__);
1360 return 0;
1363 ev = do_pth_event (PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key,
1364 pth_timeout (sec, 0));
1365 if (ev == NULL)
1367 leave_pth (__FUNCTION__);
1368 return -1;
1370 do_pth_wait (ev);
1371 do_pth_event_free (ev, PTH_FREE_ALL);
1373 leave_pth (__FUNCTION__);
1374 return 0;
1382 Some simple tests.
1384 #ifdef TEST
1385 #include <stdio.h>
1387 void * thread (void * c)
1390 Sleep (2000);
1391 SetEvent (((pth_event_t)c)->hd);
1392 fprintf (stderr, "\n\nhallo!.\n");
1393 pth_exit (NULL);
1394 return NULL;
1398 int main_1 (int argc, char ** argv)
1400 pth_attr_t t;
1401 pth_t hd;
1402 pth_event_t ev;
1404 pth_init ();
1405 ev = pth_event (0, NULL);
1406 t = pth_attr_new ();
1407 pth_attr_set (t, PTH_ATTR_JOINABLE, 1);
1408 pth_attr_set (t, PTH_ATTR_STACK_SIZE, 4096);
1409 pth_attr_set (t, PTH_ATTR_NAME, "hello");
1410 hd = pth_spawn (t, thread, ev);
1412 pth_wait (ev);
1413 pth_attr_destroy (t);
1414 pth_event_free (ev, 0);
1415 pth_kill ();
1417 return 0;
1421 static pth_event_t
1422 setup_signals (struct sigset_s *sigs, int *signo)
1424 pth_event_t ev;
1426 sigemptyset (sigs);
1427 sigaddset (sigs, SIGINT);
1428 sigaddset (sigs, SIGTERM);
1430 ev = pth_event (PTH_EVENT_SIGS, sigs, signo);
1431 return ev;
1435 main_2 (int argc, char ** argv)
1437 pth_event_t ev;
1438 struct sigset_s sigs;
1439 int signo = 0;
1441 pth_init ();
1442 ev = setup_signals (&sigs, &signo);
1443 pth_wait (ev);
1444 if (pth_event_occured (ev) && signo)
1445 fprintf (stderr, "signal caught! signo %d\n", signo);
1447 pth_event_free (ev, PTH_FREE_ALL);
1448 pth_kill ();
1449 return 0;
1453 main_3 (int argc, char ** argv)
1455 struct sockaddr_in addr, rem;
1456 int fd, n = 0, infd;
1457 int signo = 0;
1458 struct sigset_s sigs;
1459 pth_event_t ev;
1461 pth_init ();
1462 fd = socket (AF_INET, SOCK_STREAM, 0);
1464 memset (&addr, 0, sizeof addr);
1465 addr.sin_addr.s_addr = INADDR_ANY;
1466 addr.sin_port = htons (5050);
1467 addr.sin_family = AF_INET;
1468 bind (fd, (struct sockaddr*)&addr, sizeof addr);
1469 listen (fd, 5);
1471 ev = setup_signals (&sigs, &signo);
1472 n = sizeof addr;
1473 infd = pth_accept_ev (fd, (struct sockaddr *)&rem, &n, ev);
1474 fprintf (stderr, "infd %d: %s:%d\n", infd, inet_ntoa (rem.sin_addr),
1475 htons (rem.sin_port));
1477 closesocket (infd);
1478 pth_event_free (ev, PTH_FREE_ALL);
1479 pth_kill ();
1480 return 0;
1484 main (int argc, char ** argv)
1486 pth_event_t ev;
1487 pth_key_t ev_key;
1489 pth_init ();
1490 /*ev = pth_event (PTH_EVENT_TIME, &ev_key, pth_timeout (5, 0));
1491 pth_wait (ev);
1492 pth_event_free (ev, PTH_FREE_ALL);*/
1493 pth_sleep (5);
1494 pth_kill ();
1495 return 0;
1497 #endif
1499 #endif /*HAVE_W32_SYSTEM*/