diff options
Diffstat (limited to 'gpgme/wait.c')
| -rw-r--r-- | gpgme/wait.c | 268 |
1 files changed, 93 insertions, 175 deletions
diff --git a/gpgme/wait.c b/gpgme/wait.c index f54209d6..d08c021a 100644 --- a/gpgme/wait.c +++ b/gpgme/wait.c @@ -33,14 +33,7 @@ #include "context.h" #include "ops.h" #include "wait.h" - -#define DEBUG_SELECT_ENABLED 1 - -#if DEBUG_SELECT_ENABLED -# define DEBUG_SELECT(a) fprintf a -#else -# define DEBUG_SELECT(a) do { } while(0) -#endif +#include "io.h" /* Fixme: implement the following stuff to make the code MT safe. * To avoid the need to link against a specific threads lib, such @@ -52,55 +45,36 @@ * */ #define enter_crit() do { } while (0) #define leave_crit() do { } while (0) -#define lock_queue() do { } while (0) -#define unlock_queue() do { } while (0) +#define lock_table() do { } while (0) +#define unlock_table() do { } while (0) + -struct wait_queue_item_s { - struct wait_queue_item_s *next; - volatile int used; +struct wait_item_s { volatile int active; int (*handler)(void*,pid_t,int); void *handler_value; pid_t pid; - int fd; - int inbound; /* this is an inbound data handler fd */ - + int inbound; /* this is an inbound data handler fd */ int exited; int exit_status; int exit_signal; - GpgmeCtx ctx; }; +static int fd_table_size; +static struct io_select_fd_s *fd_table; -static struct wait_queue_item_s wait_queue[SIZEOF_WAIT_QUEUE]; - -static int the_big_select ( void ); - - -static void -init_wait_queue (void) -{ - int i; - static int initialized = 0; - - if ( initialized ) /* FIXME: This leads to a race */ - return; +static int do_select ( void ); - lock_queue (); - for (i=1; i < SIZEOF_WAIT_QUEUE; i++ ) - wait_queue[i-1].next = &wait_queue[i]; - initialized = 1; - unlock_queue(); -} -static struct wait_queue_item_s * +static struct wait_item_s * queue_item_from_context ( GpgmeCtx ctx ) { - struct wait_queue_item_s *q; + struct wait_item_s *q; + int i; - for (q=wait_queue; q; q = q->next) { - if ( q->used && q->ctx == ctx ) + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->ctx == ctx ) return q; } return NULL; @@ -108,12 +82,14 @@ queue_item_from_context ( GpgmeCtx ctx ) static void -propagate_term_results ( const struct wait_queue_item_s *first_q ) +propagate_term_results ( const struct wait_item_s *first_q ) { - struct wait_queue_item_s *q; + struct wait_item_s *q; + int i; - for (q=wait_queue; q; q = q->next) { - if ( q->used && q != first_q && !q->exited + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) + && q != first_q && !q->exited && q->pid == first_q->pid ) { q->exited = first_q->exited; q->exit_status = first_q->exit_status; @@ -125,11 +101,12 @@ propagate_term_results ( const struct wait_queue_item_s *first_q ) static int count_active_fds ( pid_t pid ) { - struct wait_queue_item_s *q; - int count = 0; + struct wait_item_s *q; + int i, count = 0; - for (q=wait_queue; q; q = q->next) { - if ( q->used && q->active && q->pid == pid ) + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) + && q->active && q->pid == pid ) count++; } return count; @@ -140,14 +117,15 @@ count_active_fds ( pid_t pid ) static void remove_process ( pid_t pid ) { - struct wait_queue_item_s *q; - - for (q=wait_queue; q; q = q->next) { - if ( q->used ) { - close (q->fd); - q->handler = NULL; - q->ctx = NULL; - q->used = 0; + struct wait_item_s *q; + int i; + + for (i=0; i < fd_table_size; i++ ) { + if (fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->pid == pid ) { + xfree (q); + fd_table[i].opaque = NULL; + close (fd_table[i].fd); + fd_table[i].fd = -1; } } } @@ -176,19 +154,16 @@ gpgme_wait ( GpgmeCtx c, int hang ) GpgmeCtx _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond ) { - struct wait_queue_item_s *q; + struct wait_item_s *q; - init_wait_queue (); do { - int did_work = the_big_select(); + int did_work = do_select(); if ( cond && *cond ) hang = 0; if ( !did_work ) { - int status; - - /* We did no read/write - see whether this process is still + /* We did no read/write - see whether the process is still * alive */ assert (c); /* !c is not yet implemented */ q = queue_item_from_context ( c ); @@ -196,19 +171,9 @@ _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond ) if (q->exited) ; - else if ( waitpid ( q->pid, &status, WNOHANG ) == q->pid ) { + else if ( _gpgme_io_waitpid (q->pid, 0, + &q->exit_status, &q->exit_signal)){ q->exited = 1; - if ( WIFSIGNALED (status) ) { - q->exit_status = 4; /* Need some value here */ - q->exit_signal = WTERMSIG (status); - } - else if ( WIFEXITED (status) ) { - q->exit_status = WEXITSTATUS (status); - } - else { - q->exited++; - q->exit_status = 4; - } propagate_term_results (q); } @@ -234,99 +199,34 @@ _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond ) * gpgs. A future version might provide a facility to delegate * those selects to the GDK select stuff. * This function must be called only by one thread!! - * FIXME: The data structures and algorithms are stupid. * Returns: 0 = nothing to run * 1 = did run something */ static int -the_big_select ( void ) +do_select ( void ) { - static fd_set readfds; - static fd_set writefds; - struct wait_queue_item_s *q; - int max_fd, n; - struct timeval timeout = { 1, 0 }; /* Use a one second timeout */ - - FD_ZERO ( &readfds ); - FD_ZERO ( &writefds ); - max_fd = 0; - + struct wait_item_s *q; + int i, n; - DEBUG_SELECT ((stderr, "gpgme:select on [ ")); - lock_queue (); - for ( q = wait_queue; q; q = q->next ) { - if ( q->used && q->active ) { - if (q->inbound) { - assert ( !FD_ISSET ( q->fd, &readfds ) ); - FD_SET ( q->fd, &readfds ); - DEBUG_SELECT ((stderr, "r%d ", q->fd )); - } - else { - assert ( !FD_ISSET ( q->fd, &writefds ) ); - FD_SET ( q->fd, &writefds ); - DEBUG_SELECT ((stderr, "w%d ", q->fd )); - } - if ( q->fd > max_fd ) - max_fd = q->fd; - } - } - unlock_queue (); - DEBUG_SELECT ((stderr, "]\n" )); - - n = select ( max_fd+1, &readfds, &writefds, NULL, &timeout ); - if ( n <= 0 ) { - if ( n && errno != EINTR ) { - fprintf (stderr, "the_big_select: select failed: %s\n", - strerror (errno) ); - } - return 0; - } + n = _gpgme_io_select ( fd_table, fd_table_size ); + if ( n <= 0 ) + return 0; /* error or timeout */ -#if DEBUG_SELECT_ENABLED - { - int i; - - fprintf (stderr, "gpgme:select OK [ " ); - for (i=0; i <= max_fd; i++ ) { - if (FD_ISSET (i, &readfds) ) - fprintf (stderr, "r%d ", i ); - if (FD_ISSET (i, &writefds) ) - fprintf (stderr, "w%d ", i ); - } - fprintf (stderr, "]\n" ); - } -#endif - - /* something has to be done. Go over the queue and call - * the handlers */ - restart: - while ( n ) { - lock_queue (); - for ( q = wait_queue; q; q = q->next ) { - if ( q->used && q->active && q->inbound - && FD_ISSET (q->fd, &readfds ) ) { - FD_CLR (q->fd, &readfds ); - assert (n); - n--; - unlock_queue (); - if ( q->handler (q->handler_value, q->pid, q->fd ) ) - q->active = 0; - goto restart; - } - if ( q->used && q->active && !q->inbound - && FD_ISSET (q->fd, &writefds ) ) { - FD_CLR (q->fd, &writefds ); - assert (n); - n--; - unlock_queue (); - if ( q->handler (q->handler_value, q->pid, q->fd ) ) - q->active = 0; - goto restart; + for (i=0; i < fd_table_size && n; i++ ) { + if ( fd_table[i].fd != -1 && fd_table[i].signaled ) { + q = fd_table[i].opaque; + assert (n); + n--; + if ( q->active && q->handler (q->handler_value, + q->pid, fd_table[i].fd ) ) { + q->active = 0; + fd_table[i].for_read = 0; + fd_table[i].for_write = 0; } } - unlock_queue (); } + return 1; } @@ -342,35 +242,53 @@ _gpgme_register_pipe_handler( void *opaque, pid_t pid, int fd, int inbound ) { GpgmeCtx ctx = opaque; - struct wait_queue_item_s *q; + struct wait_item_s *q; + int i; - init_wait_queue(); assert (opaque); assert (handler); - lock_queue (); - for ( q = wait_queue; q; q = q->next ) { - if ( !q->used ) { - q->used = 1; - q->active = 0; - break; - } - } - unlock_queue (); - if ( !q ) - return mk_error (Too_Many_Procs); - - q->fd = fd; + q = xtrycalloc ( 1, sizeof *q ); + if ( !q ) + return mk_error (Out_Of_Core); q->inbound = inbound; q->handler = handler; q->handler_value = handler_value; q->pid = pid; q->ctx = ctx; - - /* and enable this entry for the next select */ - q->exited = 0; q->active = 1; - return 0; + + lock_table (); + again: + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd == -1 ) { + fd_table[i].fd = fd; + fd_table[i].for_read = inbound; + fd_table[i].for_write = !inbound; + fd_table[i].signaled = 0; + fd_table[i].opaque = q; + unlock_table (); + return 0; + } + } + if ( fd_table_size < 50 ) { + /* FIXME: We have to wait until there are no other readers of the + * table, i.e that the io_select is not active in another thread */ + struct io_select_fd_s *tmp; + + tmp = xtryrealloc ( fd_table, (fd_table_size + 10) * sizeof *tmp ); + if ( tmp ) { + for (i=0; i < 10; i++ ) + tmp[fd_table_size+i].fd = -1; + fd_table_size += i; + fd_table = tmp; + goto again; + } + } + + unlock_table (); + xfree (q); + return mk_error (Too_Many_Procs); } |
