2 * Copyright (C) 2000 Werner Koch (dd9jn)
4 * This file is part of GPGME.
6 * GPGME is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GPGME is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
28 #include <sys/types.h>
36 /* Fixme: implement the following stuff to make the code MT safe.
37 * To avoid the need to link against a specific threads lib, such
38 * an implementation should require the caller to register a function
39 * which does this task.
40 * enter_crit() and leave_crit() are used to embrace an area of code
41 * which should be executed only by one thread at a time.
42 * lock_xxxx() and unlock_xxxx() protect access to an data object.
44 #define enter_crit() do { } while (0)
45 #define leave_crit() do { } while (0)
46 #define lock_queue() do { } while (0)
47 #define unlock_queue() do { } while (0)
49 struct wait_queue_item_s {
50 struct wait_queue_item_s *next;
53 int (*handler)(void*,pid_t,int);
57 int inbound; /* this is an inbound data handler fd */
67 static struct wait_queue_item_s wait_queue[SIZEOF_WAIT_QUEUE];
69 static int the_big_select ( void );
73 init_wait_queue (void)
76 static int initialized = 0;
78 if ( initialized ) /* FIXME: This leads to a race */
82 for (i=1; i < SIZEOF_WAIT_QUEUE; i++ )
83 wait_queue[i-1].next = &wait_queue[i];
88 static struct wait_queue_item_s *
89 queue_item_from_context ( GpgmeCtx ctx )
91 struct wait_queue_item_s *q;
93 for (q=wait_queue; q; q = q->next) {
94 if ( q->used && q->ctx == ctx )
106 * Wait for a finished request, if @c is given the function does only
107 * wait on a finsihed request for that context, otherwise it will return
108 * on any request. When @hang is true the function will wait, otherwise
109 * it will return immediately when there is no pending finished request.
111 * Return value: Context of the finished request or NULL if @hang is false
112 * and no (or the given) request has finished.
115 gpgme_wait ( GpgmeCtx c, int hang )
117 struct wait_queue_item_s *q;
121 if ( !the_big_select() ) {
124 /* We did no read/write - see whether this process is still
126 assert (c); /* !c is not yet implemented */
127 q = queue_item_from_context ( c );
130 if ( waitpid ( q->pid, &status, WNOHANG ) == q->pid ) {
132 if ( WIFSIGNALED (status) ) {
133 q->exit_status = 4; /* Need some value here */
134 q->exit_signal = WTERMSIG (status);
136 else if ( WIFEXITED (status) ) {
137 q->exit_status = WEXITSTATUS (status);
143 /* okay, the process has terminated - we are ready */
154 * We use this function to do the select stuff for all running
155 * gpgs. A future version might provide a facility to delegate
156 * those selects to the GDK select stuff.
157 * This function must be called only by one thread!!
158 * FIXME: The data structures and algorithms are stupid.
159 * Returns: 0 = nothing to run
160 * 1 = did run something
164 the_big_select ( void )
166 static fd_set readfds;
167 static fd_set writefds;
168 struct wait_queue_item_s *q;
170 struct timeval timeout = { 1, 0 }; /* Use a one second timeout */
172 FD_ZERO ( &readfds );
173 FD_ZERO ( &writefds );
176 for ( q = wait_queue; q; q = q->next ) {
177 if ( q->used && q->active ) {
179 assert ( !FD_ISSET ( q->fd, &readfds ) );
180 FD_SET ( q->fd, &readfds );
183 assert ( !FD_ISSET ( q->fd, &writefds ) );
184 FD_SET ( q->fd, &writefds );
186 if ( q->fd > max_fd )
193 n = select ( max_fd+1, &readfds, &writefds, NULL, &timeout );
195 if ( n && errno != EINTR ) {
196 fprintf (stderr, "the_big_select: select failed: %s\n",
202 /* something has to be done. Go over the queue and call
207 for ( q = wait_queue; q; q = q->next ) {
208 if ( q->used && q->active
209 && FD_ISSET (q->fd, q->inbound? &readfds : &writefds ) ) {
210 FD_CLR (q->fd, q->inbound? &readfds : &writefds );
214 if ( q->handler (q->handler_value, q->pid, q->fd ) )
227 * called by rungpg.c to register something for select()
230 _gpgme_register_pipe_handler( void *opaque,
231 int (*handler)(void*,pid_t,int),
233 pid_t pid, int fd, int inbound )
235 GpgmeCtx ctx = opaque;
236 struct wait_queue_item_s *q;
243 for ( q = wait_queue; q; q = q->next ) {
252 return mk_error (Too_Many_Procs);
255 q->inbound = inbound;
256 q->handler = handler;
257 q->handler_value = handler_value;
261 /* and enable this entry for the next select */