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>
38 /* Fixme: implement the following stuff to make the code MT safe.
39 * To avoid the need to link against a specific threads lib, such
40 * an implementation should require the caller to register a function
41 * which does this task.
42 * enter_crit() and leave_crit() are used to embrace an area of code
43 * which should be executed only by one thread at a time.
44 * lock_xxxx() and unlock_xxxx() protect access to an data object.
46 #define enter_crit() do { } while (0)
47 #define leave_crit() do { } while (0)
48 #define lock_table() do { } while (0)
49 #define unlock_table() do { } while (0)
54 int (*handler)(void*,pid_t,int);
57 int inbound; /* this is an inbound data handler fd */
64 static int fd_table_size;
65 static struct io_select_fd_s *fd_table;
67 static int do_select ( void );
70 static struct wait_item_s *
71 queue_item_from_context ( GpgmeCtx ctx )
73 struct wait_item_s *q;
76 for (i=0; i < fd_table_size; i++ ) {
77 if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->ctx == ctx )
85 propagate_term_results ( const struct wait_item_s *first_q )
87 struct wait_item_s *q;
90 for (i=0; i < fd_table_size; i++ ) {
91 if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque)
92 && q != first_q && !q->exited
93 && q->pid == first_q->pid ) {
94 q->exited = first_q->exited;
95 q->exit_status = first_q->exit_status;
96 q->exit_signal = first_q->exit_signal;
102 count_active_fds ( pid_t pid )
104 struct wait_item_s *q;
107 for (i=0; i < fd_table_size; i++ ) {
108 if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque)
109 && q->active && q->pid == pid )
116 /* remove the given process from the queue */
118 remove_process ( pid_t pid )
120 struct wait_item_s *q;
123 for (i=0; i < fd_table_size; i++ ) {
124 if (fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->pid == pid ) {
126 fd_table[i].opaque = NULL;
127 close (fd_table[i].fd);
140 * Wait for a finished request, if @c is given the function does only
141 * wait on a finsihed request for that context, otherwise it will return
142 * on any request. When @hang is true the function will wait, otherwise
143 * it will return immediately when there is no pending finished request.
145 * Return value: Context of the finished request or NULL if @hang is false
146 * and no (or the given) request has finished.
149 gpgme_wait ( GpgmeCtx c, int hang )
151 return _gpgme_wait_on_condition ( c, hang, NULL );
155 _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond )
157 struct wait_item_s *q;
160 int did_work = do_select();
166 /* We did no read/write - see whether the process is still
168 assert (c); /* !c is not yet implemented */
169 q = queue_item_from_context ( c );
174 else if ( _gpgme_io_waitpid (q->pid, 0,
175 &q->exit_status, &q->exit_signal)){
177 propagate_term_results (q);
181 if ( !count_active_fds (q->pid) ) {
182 /* Hmmm, as long as we don't have a callback for
183 * the exit status, we have no use for these
184 * values and therefore we can remove this from
186 remove_process (q->pid);
198 * We use this function to do the select stuff for all running
199 * gpgs. A future version might provide a facility to delegate
200 * those selects to the GDK select stuff.
201 * This function must be called only by one thread!!
202 * Returns: 0 = nothing to run
203 * 1 = did run something
209 struct wait_item_s *q;
212 n = _gpgme_io_select ( fd_table, fd_table_size );
214 return 0; /* error or timeout */
216 for (i=0; i < fd_table_size && n; i++ ) {
217 if ( fd_table[i].fd != -1 && fd_table[i].signaled ) {
218 q = fd_table[i].opaque;
221 if ( q->active && q->handler (q->handler_value,
222 q->pid, fd_table[i].fd ) ) {
224 fd_table[i].for_read = 0;
225 fd_table[i].for_write = 0;
236 * called by rungpg.c to register something for select()
239 _gpgme_register_pipe_handler( void *opaque,
240 int (*handler)(void*,pid_t,int),
242 pid_t pid, int fd, int inbound )
244 GpgmeCtx ctx = opaque;
245 struct wait_item_s *q;
251 q = xtrycalloc ( 1, sizeof *q );
253 return mk_error (Out_Of_Core);
254 q->inbound = inbound;
255 q->handler = handler;
256 q->handler_value = handler_value;
263 for (i=0; i < fd_table_size; i++ ) {
264 if ( fd_table[i].fd == -1 ) {
266 fd_table[i].for_read = inbound;
267 fd_table[i].for_write = !inbound;
268 fd_table[i].signaled = 0;
269 fd_table[i].opaque = q;
274 if ( fd_table_size < 50 ) {
275 /* FIXME: We have to wait until there are no other readers of the
276 * table, i.e that the io_select is not active in another thread */
277 struct io_select_fd_s *tmp;
279 tmp = xtryrealloc ( fd_table, (fd_table_size + 10) * sizeof *tmp );
281 for (i=0; i < 10; i++ )
282 tmp[fd_table_size+i].fd = -1;
291 return mk_error (Too_Many_Procs);