diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index cc3ec9f4f..b33b7842f 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,8 @@ +2004-12-13 Werner Koch + + * w32-pth.c, w32-pth.h: Added real code written by Timo Schulz. + Not finished, though. + 2004-12-07 Werner Koch * w32-pth.c, w32-pth.h: New. diff --git a/jnlib/w32-pth.c b/jnlib/w32-pth.c index c23cebf4a..80a58d859 100644 --- a/jnlib/w32-pth.c +++ b/jnlib/w32-pth.c @@ -1,4 +1,5 @@ /* w32-pth.c - GNU Pth emulation for W32 (MS Windows). + * Copyright (c) 1999-2003 Ralf S. Engelschall * Copyright (C) 2004 g10 Code GmbH * * This file is part of GnuPG. @@ -16,6 +17,12 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * ------------------------------------------------------------------ + * This code is based on Ralf Engelschall's GNU Pth, a non-preemptive + * thread scheduling library which can be found at + * http://www.gnu.org/software/pth/. MS Windows (W32) specific code + * written by Timo Schulz, g10 Code. */ #include @@ -23,20 +30,1054 @@ #include #include #include +#include +/* We don't want to have any Windows specific code in the header, thus + we use a macro which defaults to a compatible type in w32-pth.h. */ +#define W32_PTH_HANDLE_INTERNAL HANDLE #include "w32-pth.h" -ssize_t -pth_read (int fd, void *buffer, size_t size) + +static int pth_signo = 0; +static HANDLE pth_signo_ev = NULL; +static int pth_initialized = 0; + + + +#define implicit_init() do { if (!pth_initialized) pth_init(); } while (0) + + + +struct pth_event_s { - return read (fd, buffer, size); + struct pth_event_s * next; + struct pth_event_s * prev; + HANDLE hd; + union { + struct sigset_s * sig; + int fd; + struct timeval tv; + pth_mutex_t * mx; + } u; + int * val; + int u_type; + int flags; +}; + + +struct pth_attr_s +{ + unsigned int flags; + unsigned int stack_size; + char * name; +}; + + + +int +pth_init (void) +{ + SECURITY_ATTRIBUTES sa; + WSADATA wsadat; + + printf ("pth_init: called.\n"); + pth_initialized = 1; + if (WSAStartup (0x202, &wsadat)) + return -1; + pth_signo = 0; + if (pth_signo_ev) + CloseHandle (pth_signo_ev); + memset (&sa, 0, sizeof sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + sa.nLength = sizeof sa; + pth_signo_ev = CreateEvent (&sa, TRUE, FALSE, NULL); + + return 0; } -ssize_t -pth_write (int fd, const void *buffer, size_t size) + +int +pth_kill (void) { - return write (fd, buffer, size); + pth_signo = 0; + if (pth_signo_ev) + CloseHandle (pth_signo_ev); + WSACleanup (); + pth_initialized = 0; + return 0; } +long +pth_ctrl (unsigned long query, ...) +{ + implicit_init (); + + switch (query) { + case PTH_CTRL_GETAVLOAD: + case PTH_CTRL_GETPRIO: + case PTH_CTRL_GETNAME: + case PTH_CTRL_GETTHREADS_NEW: + case PTH_CTRL_GETTHREADS_READY: + case PTH_CTRL_GETTHREADS_RUNNING: + case PTH_CTRL_GETTHREADS_WAITING: + case PTH_CTRL_GETTHREADS_SUSPENDED: + case PTH_CTRL_GETTHREADS_DEAD: + /*case PTH_CTRL_GETTHREADS:*/ + default: + return -1; + } + return 0; +} + + + +pth_time_t +pth_timeout (long sec, long usec) +{ + pth_time_t tvd; + + tvd.tv_sec = sec; + tvd.tv_usec = usec; + return tvd; +} + + +int +pth_read_ev (int fd, void *buffer, size_t size, pth_event_t ev) +{ + implicit_init (); + return 0; +} + + +int +pth_read (int fd, void * buffer, size_t size) +{ + int n; + + implicit_init (); + n = recv (fd, buffer, size, 0); + if (n == -1 && WSAGetLastError () == WSAENOTSOCK) { + DWORD nread = 0; + n = ReadFile ((HANDLE)fd, buffer, size, &nread, NULL); + if (!n) + return -1; + return (int)nread; + } + return n; +} + + +int +pth_write_ev (int fd, const void *buffer, size_t size, pth_event_t ev) +{ + implicit_init (); + return 0; +} + + +int +pth_write (int fd, const void * buffer, size_t size) +{ + int n; + + implicit_init (); + n = send (fd, buffer, size, 0); + if (n == -1 && WSAGetLastError () == WSAENOTSOCK) { + DWORD nwrite; + n = WriteFile ((HANDLE)fd, buffer, size, &nwrite, NULL); + if (!n) + return -1; + return (int)nwrite; + } + return n; +} + + +int +pth_select (int nfds, fd_set * rfds, fd_set * wfds, fd_set * efds, + const struct timeval * timeout) +{ + implicit_init (); + return select (nfds, rfds, wfds, efds, timeout); +} + + +int +pth_fdmode (int fd, int mode) +{ + unsigned long val; + + implicit_init (); + /* XXX: figure out original fd mode */ + switch (mode) { + case PTH_FDMODE_NONBLOCK: + val = 1; + if (ioctlsocket (fd, FIONBIO, &val) == SOCKET_ERROR) + return PTH_FDMODE_ERROR; + break; + + case PTH_FDMODE_BLOCK: + val = 0; + if (ioctlsocket (fd, FIONBIO, &val) == SOCKET_ERROR) + return PTH_FDMODE_ERROR; + break; + } + return PTH_FDMODE_BLOCK; +} + + +int +pth_accept (int fd, struct sockaddr *addr, int *addrlen) +{ + implicit_init (); + return accept (fd, addr, addrlen); +} + + +int +pth_accept_ev (int fd, struct sockaddr *addr, int *addrlen, pth_event_t ev_extra) +{ + pth_key_t ev_key; + pth_event_t ev; + int rv; + int fdmode; + + implicit_init (); + + fdmode = pth_fdmode (fd, PTH_FDMODE_NONBLOCK); + if (fdmode == PTH_FDMODE_ERROR) + return -1; + + ev = NULL; + while ((rv = accept (fd, addr, addrlen)) == -1 && + (WSAGetLastError () == WSAEINPROGRESS || + WSAGetLastError () == WSAEWOULDBLOCK)) { + if (ev == NULL) { + ev = pth_event (PTH_EVENT_FD|PTH_UNTIL_FD_READABLE|PTH_MODE_STATIC, &ev_key, fd); + if (ev == NULL) + return -1; + if (ev_extra != NULL) + pth_event_concat (ev, ev_extra, NULL); + } + /* wait until accept has a chance */ + pth_wait (ev); + if (ev_extra != NULL) { + pth_event_isolate (ev); + if (pth_event_status (ev) != PTH_STATUS_OCCURRED) { + pth_fdmode (fd, fdmode); + return -1; + } + } + } + + pth_fdmode (fd, fdmode); + return rv; +} + + +int +pth_connect (int fd, struct sockaddr *name, int namelen) +{ + implicit_init (); + return connect (fd, name, namelen); +} + + +int +pth_mutex_release (pth_mutex_t *hd) +{ + if (!hd) + return -1; + implicit_init (); + if (hd->mx) { + CloseHandle (hd->mx); + hd->mx = NULL; + } + free (hd); + return 0; +} + + +int +pth_mutex_acquire (pth_mutex_t *hd, int tryonly, pth_event_t ev_extra) +{ + implicit_init (); + + if (!hd) + return -1; + if (!hd->mx) + return -1; + +#if 0 + /* still not locked, so simply acquire mutex? */ + if (!(mutex->mx_state & PTH_MUTEX_LOCKED)) { + mutex->mx_state |= PTH_MUTEX_LOCKED; + mutex->mx_count = 1; + pth_ring_append(&(pth_current->mutexring), &(mutex->mx_node)); + pth_debug1("pth_mutex_acquire: immediately locking mutex"); + return 0; + } + + /* already locked by caller? */ + if (mutex->mx_count >= 1 && mutex->mx_owner == pth_current) { + /* recursive lock */ + mutex->mx_count++; + pth_debug1("pth_mutex_acquire: recursive locking"); + return 0; + } + + if (tryonly) + return return -1; + + for (;;) { + ev = pth_event(PTH_EVENT_MUTEX|PTH_MODE_STATIC, &ev_key, mutex); + if (ev_extra != NULL) + pth_event_concat (ev, ev_extra, NULL); + pth_wait (ev); + if (ev_extra != NULL) { + pth_event_isolate (ev); + if (pth_event_status(ev) == PTH_STATUS_PENDING) + return return -1; + } + if (!(mutex->mx_state & PTH_MUTEX_LOCKED)) + break; + } +#endif + + hd->mx_state |= PTH_MUTEX_LOCKED; + return 0; +} + + +int +pth_mutex_init (pth_mutex_t *hd) +{ + SECURITY_ATTRIBUTES sa; + implicit_init (); + if (hd->mx) { + ReleaseMutex (hd->mx); + CloseHandle (hd->mx); + } + memset (&sa, 0, sizeof sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + sa.nLength = sizeof sa; + hd->mx = CreateMutex (&sa, FALSE, NULL); + hd->mx_state = PTH_MUTEX_INITIALIZED; + return 0; +} + + +pth_attr_t +pth_attr_new (void) +{ + pth_attr_t hd; + + implicit_init (); + hd = calloc (1, sizeof *hd); + if (!hd) + return NULL; + return hd; +} + + +int +pth_attr_destroy (pth_attr_t hd) +{ + if (!hd) + return -1; + implicit_init (); + if (hd->name) + free (hd->name); + free (hd); + return 0; +} + + +int +pth_attr_set (pth_attr_t hd, int field, ...) +{ + va_list args; + char * str; + int val; + int rc = 0; + + implicit_init (); + va_start (args, field); + switch (field) { + case PTH_ATTR_JOINABLE: + val = va_arg (args, int); + if (val) { + hd->flags |= PTH_ATTR_JOINABLE; + printf ("pth_attr_set: PTH_ATTR_JOINABLE\n"); + } + break; + + case PTH_ATTR_STACK_SIZE: + val = va_arg (args, int); + if (val) { + hd->flags |= PTH_ATTR_STACK_SIZE; + hd->stack_size = val; + printf ("pth_attr_set: PTH_ATTR_STACK_SIZE %d\n", val); + } + break; + + case PTH_ATTR_NAME: + str = va_arg (args, char*); + if (hd->name) + free (hd->name); + if (str) { + hd->name = strdup (str); + if (!hd->name) + return -1; + hd->flags |= PTH_ATTR_NAME; + printf ("pth_attr_set: PTH_ATTR_NAME %s\n", hd->name); + } + break; + + default: + rc = -1; + break; + } + va_end (args); + return rc; +} + + +pth_t +pth_spawn (pth_attr_t hd, void *(*func)(void *), void *arg) +{ + SECURITY_ATTRIBUTES sa; + DWORD tid; + HANDLE th; + + if (!hd) + return NULL; + + implicit_init (); + + memset (&sa, 0, sizeof sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + sa.nLength = sizeof sa; + + th = CreateThread (&sa, hd->stack_size, (LPTHREAD_START_ROUTINE)func, arg, 0, &tid); + return th; +} + + +int +pth_join (pth_t hd, void **value) +{ + return 0; +} + + +/* friendly */ +int +pth_cancel (pth_t hd) +{ + if (!hd) + return -1; + implicit_init (); + WaitForSingleObject (hd, 1000); + TerminateThread (hd, 0); + return 0; +} + + +/* cruel */ +int +pth_abort (pth_t hd) +{ + if (!hd) + return -1; + implicit_init (); + TerminateThread (hd, 0); + return 0; +} + + +void +pth_exit (void *value) +{ + implicit_init (); + pth_kill (); + exit ((int)(long)value); +} + + +unsigned +pth_waitpid (unsigned pid, int * status, int options) +{ + implicit_init (); +#if 0 + pth_event_t ev; + static pth_key_t ev_key = PTH_KEY_INIT; + pid_t pid; + + pth_debug2("pth_waitpid: called from thread \"%s\"", pth_current->name); + + for (;;) { + /* do a non-blocking poll for the pid */ + while ( (pid = pth_sc(waitpid)(wpid, status, options|WNOHANG)) < 0 + && errno == EINTR) ; + + /* if pid was found or caller requested a polling return immediately */ + if (pid == -1 || pid > 0 || (pid == 0 && (options & WNOHANG))) + break; + + /* else wait a little bit */ + ev = pth_event(PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key, pth_timeout(0,250000)); + pth_wait(ev); + } + + pth_debug2("pth_waitpid: leave to thread \"%s\"", pth_current->name); +#endif + return 0; +} + + +static BOOL WINAPI +sig_handler (DWORD signo) +{ + switch (signo) { + case CTRL_C_EVENT: pth_signo = SIGINT; break; + case CTRL_BREAK_EVENT: pth_signo = SIGTERM; break; + } + SetEvent (pth_signo_ev); + printf ("sig_handler=%d\n", pth_signo); + return TRUE; +} + + +pth_event_t +pth_event (unsigned long spec, ...) +{ + va_list arg; + SECURITY_ATTRIBUTES sa; + pth_event_t ev; + int rc; + + implicit_init (); + printf ("pth_event spec=%lu\n", spec); + va_start (arg, spec); + ev = calloc (1, sizeof *ev); + if (!ev) + return NULL; + if (spec == 0) + ; + else if (spec & PTH_EVENT_SIGS) { + ev->u.sig = va_arg (arg, struct sigset_s *); + ev->u_type = PTH_EVENT_SIGS; + ev->val = va_arg (arg, int *); + rc = SetConsoleCtrlHandler (sig_handler, TRUE); + printf ("pth_event: sigs rc=%d\n", rc); + } + else if (spec & PTH_EVENT_FD) { + if (spec & PTH_UNTIL_FD_READABLE) + ev->flags |= PTH_UNTIL_FD_READABLE; + if (spec & PTH_MODE_STATIC) + ev->flags |= PTH_MODE_STATIC; + ev->u_type = PTH_EVENT_FD; + va_arg (arg, pth_key_t); + ev->u.fd = va_arg (arg, int); + printf ("pth_event: fd=%d\n", ev->u.fd); + } + else if (spec & PTH_EVENT_TIME) { + pth_time_t t; + if (spec & PTH_MODE_STATIC) + ev->flags |= PTH_MODE_STATIC; + va_arg (arg, pth_key_t); + t = va_arg (arg, pth_time_t); + ev->u_type = PTH_EVENT_TIME; + ev->u.tv.tv_sec = t.tv_sec; + ev->u.tv.tv_usec = t.tv_usec; + } + else if (spec & PTH_EVENT_MUTEX) { + va_arg (arg, pth_key_t); + ev->u_type = PTH_EVENT_MUTEX; + ev->u.mx = va_arg (arg, pth_mutex_t*); + } + va_end (arg); + + memset (&sa, 0, sizeof sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + sa.nLength = sizeof sa; + ev->hd = CreateEvent (&sa, FALSE, FALSE, NULL); + if (!ev->hd) { + free (ev); + return NULL; + } + + return ev; +} + + +static void +pth_event_add (pth_event_t root, pth_event_t node) +{ + pth_event_t n; + + for (n=root; n->next; n = n->next) + ; + n->next = node; +} + + +pth_event_t +pth_event_concat (pth_event_t evf, ...) +{ + pth_event_t evn; + va_list ap; + + if (!evf) + return NULL; + + implicit_init (); + va_start (ap, evf); + while ((evn = va_arg(ap, pth_event_t)) != NULL) + pth_event_add (evf, evn); + va_end (ap); + + return evf; +} + + +static int +wait_for_fd (int fd, int is_read, int nwait) +{ + struct timeval tv; + fd_set r; + fd_set w; + int n; + + FD_ZERO (&r); + FD_ZERO (&w); + FD_SET (fd, is_read ? &r : &w); + + tv.tv_sec = nwait; + tv.tv_usec = 0; + + while (1) { + n = select (fd+1, &r, &w, NULL, &tv); + printf ("wait_for_fd=%d fd %d (ec=%d)\n", n, fd, (int)WSAGetLastError ()); + if (n == -1) + break; + if (!n) + continue; + if (n == 1) { + if (is_read && FD_ISSET (fd, &r)) + break; + else if (FD_ISSET (fd, &w)) + break; + } + } + return 0; +} + + +static void * +wait_fd_thread (void * ctx) +{ + pth_event_t ev = ctx; + + wait_for_fd (ev->u.fd, ev->flags & PTH_UNTIL_FD_READABLE, 3600); + printf ("wait_fd_thread: exit.\n"); + SetEvent (ev->hd); + ExitThread (0); + return NULL; +} + + +static void * +wait_timer_thread (void * ctx) +{ + pth_event_t ev = ctx; + int n = ev->u.tv.tv_sec*1000; + Sleep (n); + SetEvent (ev->hd); + printf ("wait_timer_thread: exit.\n"); + ExitThread (0); + return NULL; +} + + +/* void */ +/* sigemptyset (struct sigset_s * ss) */ +/* { */ +/* if (ss) { */ +/* memset (ss->sigs, 0, sizeof ss->sigs); */ +/* ss->idx = 0; */ +/* } */ +/* } */ + + +/* int */ +/* sigaddset (struct sigset_s * ss, int signo) */ +/* { */ +/* if (!ss) */ +/* return -1; */ +/* if (ss->idx + 1 > 64) */ +/* return -1; */ +/* ss->sigs[ss->idx] = signo; */ +/* ss->idx++; */ +/* return 0; */ +/* } */ + + +static int +sigpresent (struct sigset_s * ss, int signo) +{ +/* int i; */ +/* for (i=0; i < ss->idx; i++) { */ +/* if (ss->sigs[i] == signo) */ +/* return 1; */ +/* } */ +/* FIXME: See how to implement it. */ + return 0; +} + + +int +pth_event_occured (pth_event_t ev) +{ + if (!ev) + return 0; + implicit_init (); + switch (ev->u_type) { + case 0: + if (WaitForSingleObject (ev->hd, 0) == WAIT_OBJECT_0) + return 1; + break; + + case PTH_EVENT_SIGS: + if (sigpresent (ev->u.sig, pth_signo) && + WaitForSingleObject (pth_signo_ev, 0) == WAIT_OBJECT_0) { + printf ("pth_event_occured: sig signaled.\n"); + (*ev->val) = pth_signo; + return 1; + } + break; + + case PTH_EVENT_FD: + if (WaitForSingleObject (ev->hd, 0) == WAIT_OBJECT_0) + return 1; + break; + } + + return 0; +} + + +int +pth_event_status (pth_event_t ev) +{ + if (!ev) + return 0; + implicit_init (); + if (pth_event_occured (ev)) + return PTH_STATUS_OCCURRED; + return 0; +} + + +int +pth_event_free (pth_event_t ev, int mode) +{ + pth_event_t n; + + implicit_init (); + if (mode == PTH_FREE_ALL) { + while (ev) { + n = ev->next; + CloseHandle (ev->hd); ev->hd = NULL; + free (ev); + ev = n; + } + } + else if (mode == PTH_FREE_THIS) { + ev->prev->next = ev->next; + ev->next->prev = ev->prev; + CloseHandle (ev->hd); ev->hd = NULL; + free (ev); + + } + return 0; +} + + +pth_event_t +pth_event_isolate (pth_event_t ev) +{ + pth_event_t ring = NULL; + + if (!ev) + return NULL; + implicit_init (); + return ring; + +} + + +static void +free_threads (HANDLE *waitbuf, int *hdidx, int n) +{ + int i; + + for (i=0; i < n; i++) + CloseHandle (waitbuf[hdidx[i]]); +} + + +static int +pth_event_count (pth_event_t ev) +{ + pth_event_t p; + int cnt=0; + + if (!ev) + return 0; + for (p=ev; p; p = p->next) + cnt++; + return cnt; +} + + +int +pth_wait (pth_event_t ev) +{ + HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS/2]; + int hdidx[MAXIMUM_WAIT_OBJECTS/2]; + DWORD n = 0; + pth_attr_t attr; + pth_event_t tmp; + int pos=0, i=0; + + if (!ev) + return 0; + + implicit_init (); + attr = pth_attr_new (); + pth_attr_set (attr, PTH_ATTR_JOINABLE, 1); + pth_attr_set (attr, PTH_ATTR_STACK_SIZE, 4096); + + printf ("pth_wait: cnt %d\n", pth_event_count (ev)); + for (tmp = ev; tmp; tmp = tmp->next) { + if (pos+1 > MAXIMUM_WAIT_OBJECTS/2) { + free_threads (waitbuf, hdidx, i); + pth_attr_destroy (attr); + return -1; + } + switch (tmp->u_type) { + case 0: + waitbuf[pos++] = tmp->hd; + break; + + case PTH_EVENT_SIGS: + waitbuf[pos++] = pth_signo_ev; + printf ("pth_wait: add signal event.\n"); + break; + + case PTH_EVENT_FD: + printf ("pth_wait: spawn event wait thread.\n"); + hdidx[i++] = pos; + waitbuf[pos++] = pth_spawn (attr, wait_fd_thread, tmp); + break; + + case PTH_EVENT_TIME: + printf ("pth_wait: spawn event timer thread.\n"); + hdidx[i++] = pos; + waitbuf[pos++] = pth_spawn (attr, wait_timer_thread, tmp); + break; + + case PTH_EVENT_MUTEX: + printf ("pth_wait: add mutex event.\n"); + hdidx[i++] = pos; + waitbuf[pos++] = tmp->u.mx->mx; + /* XXX: Use SetEvent(hd->ev) */ + break; + } + } + printf ("pth_wait: set %d\n", pos); + n = WaitForMultipleObjects (pos, waitbuf, FALSE, INFINITE); + free_threads (waitbuf, hdidx, i); + pth_attr_destroy (attr); + printf ("pth_wait: n %ld\n", n); + if (n != WAIT_TIMEOUT) + return 1; + + /* + switch (ev->u_type) { + case 0: + n = WaitForSingleObject (ev->hd, INFINITE); + if (n != WAIT_OBJECT_0) + return 1; + break; + + case PTH_EVENT_SIGS: + n = WaitForSingleObject (pth_signo_ev, INFINITE); + if (n != WAIT_OBJECT_0) + return 1; + break; + + case PTH_EVENT_FD: + if (wait_for_fd (ev->u.fd, ev->flags & PTH_UNTIL_FD_READABLE)) { + SetEvent (ev->hd); + return 1; + } + break; + + default: + return -1; + } + */ + return 0; +} + + +int +pth_sleep (int sec) +{ + static pth_key_t ev_key = PTH_KEY_INIT; + pth_event_t ev; + + implicit_init (); + if (sec == 0) + return 0; + + ev = pth_event (PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key, pth_timeout (sec, 0)); + if (ev == NULL) + return -1; + pth_wait (ev); + pth_event_free (ev, PTH_FREE_ALL); + return 0; +} + + + + + +/* + Some simple tests. + */ +#ifdef TEST +#include + +void * thread (void * c) +{ + + Sleep (2000); + SetEvent (((pth_event_t)c)->hd); + printf ("\n\nhallo!.\n"); + pth_exit (NULL); + return NULL; +} + + +int main_1 (int argc, char ** argv) +{ + pth_attr_t t; + pth_t hd; + pth_event_t ev; + + pth_init (); + ev = pth_event (0, NULL); + t = pth_attr_new (); + pth_attr_set (t, PTH_ATTR_JOINABLE, 1); + pth_attr_set (t, PTH_ATTR_STACK_SIZE, 4096); + pth_attr_set (t, PTH_ATTR_NAME, "hello"); + hd = pth_spawn (t, thread, ev); + + pth_wait (ev); + pth_attr_destroy (t); + pth_event_free (ev, 0); + pth_kill (); + + return 0; +} + + +static pth_event_t +setup_signals (struct sigset_s *sigs, int *signo) +{ + pth_event_t ev; + + sigemptyset (sigs); + sigaddset (sigs, SIGINT); + sigaddset (sigs, SIGTERM); + + ev = pth_event (PTH_EVENT_SIGS, sigs, signo); + return ev; +} + +int +main_2 (int argc, char ** argv) +{ + pth_event_t ev; + struct sigset_s sigs; + int signo = 0; + + pth_init (); + ev = setup_signals (&sigs, &signo); + pth_wait (ev); + if (pth_event_occured (ev) && signo) + printf ("signal caught! signo %d\n", signo); + + pth_event_free (ev, PTH_FREE_ALL); + pth_kill (); + return 0; +} + +int +main_3 (int argc, char ** argv) +{ + struct sockaddr_in addr, rem; + int fd, n = 0, infd; + int signo = 0; + struct sigset_s sigs; + pth_event_t ev; + + pth_init (); + fd = socket (AF_INET, SOCK_STREAM, 0); + + memset (&addr, 0, sizeof addr); + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons (5050); + addr.sin_family = AF_INET; + bind (fd, (struct sockaddr*)&addr, sizeof addr); + listen (fd, 5); + + ev = setup_signals (&sigs, &signo); + n = sizeof addr; + infd = pth_accept_ev (fd, (struct sockaddr *)&rem, &n, ev); + printf ("infd %d: %s:%d\n", infd, inet_ntoa (rem.sin_addr), htons (rem.sin_port)); + + closesocket (infd); + pth_event_free (ev, PTH_FREE_ALL); + pth_kill (); + return 0; +} + +int +main (int argc, char ** argv) +{ + pth_event_t ev; + pth_key_t ev_key; + + pth_init (); + /*ev = pth_event (PTH_EVENT_TIME, &ev_key, pth_timeout (5, 0)); + pth_wait (ev); + pth_event_free (ev, PTH_FREE_ALL);*/ + pth_sleep (5); + pth_kill (); + return 0; +} +#endif + #endif /*HAVE_W32_SYSTEM*/ + diff --git a/jnlib/w32-pth.h b/jnlib/w32-pth.h index 6b57d9bd2..efb17d255 100644 --- a/jnlib/w32-pth.h +++ b/jnlib/w32-pth.h @@ -1,5 +1,6 @@ /* w32-pth.h - GNU Pth emulation for W32 (MS Windows). - * Copyright (C) 2004 g10 Code GmbH + * Copyright (c) 1999-2003 Ralf S. Engelschall + * Copyright (C) 2004 g10 Code GmbH * * This file is part of GnuPG. * @@ -16,6 +17,11 @@ * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * ------------------------------------------------------------------ + * This code is based on Ralf Engelschall's GNU Pth, a non-preemptive + * thread scheduling library which can be found at + * http://www.gnu.org/software/pth/. */ /* Note that this header is usually used through a symlinked pth.h @@ -24,6 +30,217 @@ #ifndef W32_PTH_H #define W32_PTH_H +#include /* We need this for sockaddr et al. FIXME: too + heavyweight - may be we should factor such + code out to a second header and adjust all + user files to include it only if required. */ + +#ifndef W32_PTH_HANDLE_INTERNAL +#define W32_PTH_HANDLE_INTERNAL int +#endif + + +/* Filedescriptor blocking modes. */ +enum + { + PTH_FDMODE_ERROR = -1, + PTH_FDMODE_POLL = 0, + PTH_FDMODE_BLOCK, + PTH_FDMODE_NONBLOCK + }; + + +/* Mutex values. */ +#define PTH_MUTEX_INITIALIZED (1<<0) +#define PTH_MUTEX_LOCKED (1<<1) +#define PTH_MUTEX_INIT {{NULL, NULL}, PTH_MUTEX_INITIALIZED, NULL, 0} + + +#define PTH_KEY_INIT (1<<0) + + +/* Event subject classes. */ +#define PTH_EVENT_FD (1<<1) +#define PTH_EVENT_SELECT (1<<2) +#define PTH_EVENT_SIGS (1<<3) +#define PTH_EVENT_TIME (1<<4) +#define PTH_EVENT_MSG (1<<5) +#define PTH_EVENT_MUTEX (1<<6) +#define PTH_EVENT_COND (1<<7) +#define PTH_EVENT_TID (1<<8) +#define PTH_EVENT_FUNC (1<<9) + + + +/* Event occurrence restrictions. */ +#define PTH_UNTIL_OCCURRED (1<<11) +#define PTH_UNTIL_FD_READABLE (1<<12) +#define PTH_UNTIL_FD_WRITEABLE (1<<13) +#define PTH_UNTIL_FD_EXCEPTION (1<<14) +#define PTH_UNTIL_TID_NEW (1<<15) +#define PTH_UNTIL_TID_READY (1<<16) +#define PTH_UNTIL_TID_WAITING (1<<17) +#define PTH_UNTIL_TID_DEAD (1<<18) + + +/* Event structure handling modes. */ +#define PTH_MODE_REUSE (1<<20) +#define PTH_MODE_CHAIN (1<<21) +#define PTH_MODE_STATIC (1<<22) + + +/* Attribute commands for pth_attr_get and pth_attr_set(). */ +enum + { + PTH_ATTR_PRIO, /* RW [int] Priority of thread. */ + PTH_ATTR_NAME, /* RW [char *] Name of thread. */ + PTH_ATTR_JOINABLE, /* RW [int] Thread detachment type. */ + PTH_ATTR_CANCEL_STATE, /* RW [unsigned int] Thread cancellation state.*/ + PTH_ATTR_STACK_SIZE, /* RW [unsigned int] Stack size. */ + PTH_ATTR_STACK_ADDR, /* RW [char *] Stack lower address. */ + PTH_ATTR_DISPATCHES, /* RO [int] Total number of + thread dispatches. */ + PTH_ATTR_TIME_SPAWN, /* RO [pth_time_t] Time thread was spawned. */ + PTH_ATTR_TIME_LAST, /* RO [pth_time_t] Time thread was + last dispatched. */ + PTH_ATTR_TIME_RAN, /* RO [pth_time_t] Time thread was running. */ + PTH_ATTR_START_FUNC, /* RO [void *(*)(void *)] Thread start function.*/ + PTH_ATTR_START_ARG, /* RO [void *] Thread start argument. */ + PTH_ATTR_STATE, /* RO [pth_state_t] Scheduling state. */ + PTH_ATTR_EVENTS, /* RO [pth_event_t] Events the thread + is waiting for. */ + PTH_ATTR_BOUND /* RO [int] Whether object is + bound to thread. */ + }; + + + +/* Queries for pth_ctrl(). */ +#define PTH_CTRL_GETAVLOAD (1<<1) +#define PTH_CTRL_GETPRIO (1<<2) +#define PTH_CTRL_GETNAME (1<<3) +#define PTH_CTRL_GETTHREADS_NEW (1<<4) +#define PTH_CTRL_GETTHREADS_READY (1<<5) +#define PTH_CTRL_GETTHREADS_RUNNING (1<<6) +#define PTH_CTRL_GETTHREADS_WAITING (1<<7) +#define PTH_CTRL_GETTHREADS_SUSPENDED (1<<8) +#define PTH_CTRL_GETTHREADS_DEAD (1<<9) +#define PTH_CTRL_DUMPSTATE (1<<10) + +#define PTH_CTRL_GETTHREADS ( PTH_CTRL_GETTHREADS_NEW \ + | PTH_CTRL_GETTHREADS_READY \ + | PTH_CTRL_GETTHREADS_RUNNING \ + | PTH_CTRL_GETTHREADS_WAITING \ + | PTH_CTRL_GETTHREADS_SUSPENDED \ + | PTH_CTRL_GETTHREADS_DEAD ) + + +/* Event status codes. */ +typedef enum + { + PTH_STATUS_PENDING, + PTH_STATUS_OCCURRED, + PTH_STATUS_FAILED + } +pth_status_t; + + +/* Event deallocation types. */ +enum + { + PTH_FREE_THIS, + PTH_FREE_ALL + }; + + +/* The Pth thread handle object. */ +typedef void *pth_t; + + +/* The Mutex object. */ +struct pth_mutex_s +{ + unsigned mx_state; + W32_PTH_HANDLE_INTERNAL mx; +}; +typedef struct pth_mutex_s pth_mutex_t; + + +/* The Event object. */ +struct pth_event_s; +typedef struct pth_event_s *pth_event_t; + + +/* The Attribute object. */ +struct pth_attr_s; +typedef struct pth_attr_s *pth_attr_t; + + +/* The Key object. */ +typedef int pth_key_t; + + +/* The Pth time object. */ +typedef struct timeval pth_time_t; + + +/* Function prototypes. */ +int pth_init (void); +int pth_kill (void); +long pth_ctrl (unsigned long query, ...); + +int pth_read_ev (int fd, void *buffer, size_t size, pth_event_t ev); +int pth_read (int fd, void *buffer, size_t size); +int pth_write_ev (int fd, const void *buffer, size_t size, pth_event_t ev); +int pth_write (int fd, const void *buffer, size_t size); + +int pth_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, + const struct timeval *timeout); + +int pth_accept (int fd, struct sockaddr *addr, int *addrlen); +int pth_accept_ev (int fd, struct sockaddr *addr, int *addrlen, + pth_event_t hd); + +int pth_connect (int fd, struct sockaddr *name, int namelen); + + +int pth_mutex_release (pth_mutex_t *hd); +int pth_mutex_acquire(pth_mutex_t *hd, int try_only, pth_event_t ev_extra); +int pth_mutex_init (pth_mutex_t *hd); + + +pth_attr_t pth_attr_new (void); +int pth_attr_destroy (pth_attr_t hd); +int pth_attr_set (pth_attr_t hd, int field, ...); + +pth_t pth_spawn (pth_attr_t hd, void *(*func)(void *), void *arg); +int pth_join (pth_t hd, void **value); +int pth_abort (pth_t hd); +void pth_exit (void *value); + +unsigned int pth_waitpid (unsigned int, int *status, int options); +int pth_wait (pth_event_t hd); + +int pth_sleep (int n); +pth_time_t pth_timeout (long sec, long usec); + + + +pth_event_t pth_event_isolate (pth_event_t hd); +int pth_event_free (pth_event_t hd, int mode); +int pth_event_status (pth_event_t hd); +int pth_event_occured (pth_event_t hd); +pth_event_t pth_event_concat (pth_event_t ev, ...); +pth_event_t pth_event (unsigned long spec, ...); + + + +/*-- pth_util.c --*/ + +/* void sigemptyset (struct sigset_s * ss); */ + +/* int sigaddset (struct sigset_s * ss, int signo); */ + #endif /*W32_PTH_H*/