/[winpt]/trunk/MyGPGME/wait.c
ViewVC logotype

Annotation of /trunk/MyGPGME/wait.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 10043 byte(s)
WinPT initial checkin.


1 twoaday 2 /* wait.c
2     * Copyright (C) 2000, 2001 Werner Koch (dd9jn), g10 Code GmbH
3     * Copyright (C) 2003 Timo Schulz
4     *
5     * This file is part of MyGPGME.
6     *
7     * MyGPGME is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * MyGPGME is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20     */
21    
22     #include <stdio.h>
23     #include <stdlib.h>
24     #include <string.h>
25     #include <assert.h>
26     #include <errno.h>
27     #include <sys/types.h>
28     #include <process.h>
29     #include <io.h>
30     #include <windows.h>
31    
32     #include "util.h"
33     #include "context.h"
34     #include "ops.h"
35     #include "wait.h"
36     #include "sema.h"
37     #include "gpgme-io.h"
38     #include "rungpg.h"
39    
40     struct wait_item_s;
41     struct proc_s;
42    
43     static struct proc_s * proc_queue;
44     DEFINE_STATIC_LOCK (proc_queue_lock);
45    
46     static int fd_table_size;
47     static struct io_select_fd_s * fd_table;
48     DEFINE_STATIC_LOCK (fd_table_lock);
49    
50    
51     struct proc_s {
52     struct proc_s * next;
53     int pid;
54     gpgme_ctx_t ctx;
55     struct wait_item_s * handler_list;
56     int ready;
57     };
58    
59     struct wait_item_s {
60     struct wait_item_s *next;
61     int (*handler)(void*, int, int);
62     void *handler_value;
63     int inbound; /* this is an inbound data handler fd */
64     struct proc_s * proc; /* backlink */
65     int ready;
66     int frozen; /* copy of the frozen flag from the fd_table */
67     };
68    
69    
70     static int do_select (void);
71    
72     void
73     wait_cleanup (void)
74     {
75     DESTROY_LOCK (proc_queue_lock);
76     DESTROY_LOCK (fd_table_lock);
77     }
78    
79     /* only to be called with a locked proc_queue */
80     static int
81     count_running_fds ( struct proc_s *proc )
82     {
83     struct wait_item_s *q;
84     int count = 0;
85    
86     for (q=proc->handler_list; q; q=q->next) {
87     if ( !q->frozen && !q->ready )
88     count++;
89     }
90     return count;
91     }
92    
93     /* only to be called with a locked proc_queue */
94     static void
95     set_process_ready ( struct proc_s *proc )
96     {
97     struct wait_item_s *q, *q2;
98     int i;
99    
100     assert (proc);
101     DEBUG2 ("set_process_ready(%p) pid=%d", proc, proc->pid );
102     LOCK (fd_table_lock);
103     for (q = proc->handler_list; q; q=q2) {
104     q2 = q->next;
105     for (i=0; i < fd_table_size; i++ ) {
106     if (fd_table[i].fd != -1 && q == fd_table[i].opaque ) {
107     fd_table[i].opaque = NULL;
108     fd_table[i].fd = -1;
109     }
110     }
111     safe_free (q);
112     }
113     UNLOCK (fd_table_lock);
114     proc->handler_list = NULL;
115     proc->ready = 1;
116     }
117    
118    
119     void
120     _gpgme_remove_proc_from_wait_queue (int pid)
121     {
122     struct proc_s *proc, *last;
123    
124     DEBUG1 ("removing process %d", pid);
125     LOCK (proc_queue_lock);
126     for (last=NULL, proc=proc_queue; proc; last = proc, proc = proc->next) {
127     if (proc->pid == pid) {
128     set_process_ready (proc);
129     if (!last)
130     proc_queue = proc->next;
131     else
132     last->next = proc->next;
133     safe_free (proc);
134     break;
135     }
136     }
137     UNLOCK (proc_queue_lock);
138     }
139    
140    
141     /**
142     * gpgme_wait:
143     * @c:
144     * @hang:
145     *
146     * Wait for a finished request, if @c is given the function does only
147     * wait on a finsihed request for that context, otherwise it will return
148     * on any request. When @hang is true the function will wait, otherwise
149     * it will return immediately when there is no pending finished request.
150     *
151     * Return value: Context of the finished request or NULL if @hang is false
152     * and no (or the given) request has finished.
153     **/
154     gpgme_ctx_t
155     gpgme_wait ( gpgme_ctx_t c, int hang )
156     {
157     return _gpgme_wait_on_condition ( c, hang, NULL );
158     }
159    
160     gpgme_ctx_t
161     _gpgme_wait_on_condition (gpgme_ctx_t c, int hang, volatile int *cond)
162     {
163     DEBUG3 ("waiting... ctx=%p hang=%d cond=%p", c, hang, cond);
164     do {
165     int did_work = do_select ();
166     int any = 0;
167     struct proc_s *proc;
168    
169     if ( cond && *cond )
170     hang = 0;
171     else {
172     LOCK (proc_queue_lock);
173     for (proc=proc_queue; proc; proc = proc->next ) {
174     if (!proc->ready && !count_running_fds (proc))
175     set_process_ready (proc);
176     if (c && proc->ready && proc->ctx == c)
177     hang = 0;
178     if (!proc->ready)
179     any = 1;
180     }
181     UNLOCK (proc_queue_lock);
182     if (!any)
183     hang = 0;
184     }
185     /* fixme: we should check here for hanging processes */
186     if(hang)
187     _gpgme_gpg_housecleaning ();
188     } while (hang && !c->cancel );
189     c->cancel = 0; /* fixme: fix all functions, to return a cancel error */
190     GetExitCodeProcess ((HANDLE)( _gpgme_gpg_getpid (c->gpg)), &c->proc_rc);
191    
192     return c;
193     }
194    
195    
196    
197     /*
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
204     */
205    
206     static int
207     do_select ( void )
208     {
209     int i, n;
210     int any=0;
211    
212     n = _gpgme_io_select ( fd_table, fd_table_size );
213     if ( n <= 0 )
214     return 0; /* error or timeout */
215    
216     for (i=0; i < fd_table_size && n; i++ ) {
217     if ( fd_table[i].fd != -1 && fd_table[i].signaled
218     && !fd_table[i].frozen ) {
219     struct wait_item_s *q;
220    
221     assert (n);
222     n--;
223    
224     q = fd_table[i].opaque;
225     assert ( q );
226     assert ( q->proc );
227     assert ( !q->ready );
228     any = 1;
229     if ( q->handler (q->handler_value,
230     q->proc->pid, fd_table[i].fd ) ) {
231     DEBUG2 ("setting fd %d (q=%p) ready", fd_table[i].fd, q );
232     q->ready = 1;
233     /* free the table entry*/
234     LOCK (fd_table_lock);
235     fd_table[i].for_read = 0;
236     fd_table[i].for_write = 0;
237     fd_table[i].fd = -1;
238     fd_table[i].opaque = NULL;
239     UNLOCK (fd_table_lock);
240     }
241     }
242     }
243    
244     return any;
245     }
246    
247    
248    
249     /*
250     * called by rungpg.c to register something for select()
251     */
252     gpgme_error_t
253     _gpgme_register_pipe_handler ( void *opaque,
254     int (*handler)(void*,int,int),
255     void *handler_value,
256     int pid, int fd, int inbound )
257     {
258     gpgme_ctx_t ctx = opaque;
259     struct wait_item_s *q;
260     struct proc_s *proc;
261     int i;
262    
263     assert (opaque);
264     assert (handler);
265    
266     /* Allocate a structure to hold info about the handler */
267     q = calloc ( 1, sizeof *q );
268     if ( !q )
269     return mk_error (Out_Of_Core);
270     q->inbound = inbound;
271     q->handler = handler;
272     q->handler_value = handler_value;
273    
274     /* Put this into the process queue */
275     LOCK (proc_queue_lock);
276     for (proc=proc_queue; proc && proc->pid != pid; proc = proc->next)
277     ;
278     if (!proc) { /* a new process */
279     proc = calloc ( 1, sizeof *proc );
280     if (!proc) {
281     UNLOCK (proc_queue_lock);
282     return mk_error (Out_Of_Core);
283     }
284     proc->pid = pid;
285     proc->ctx = ctx;
286     proc->next = proc_queue;
287     proc_queue = proc;
288     }
289     assert (proc->ctx == ctx);
290     q->proc = proc;
291     q->next = proc->handler_list;
292     proc->handler_list = q;
293     UNLOCK (proc_queue_lock);
294    
295     LOCK (fd_table_lock);
296     again:
297     for (i=0; i < fd_table_size; i++ ) {
298     if ( fd_table[i].fd == -1 ) {
299     fd_table[i].fd = fd;
300     fd_table[i].for_read = inbound;
301     fd_table[i].for_write = !inbound;
302     fd_table[i].signaled = 0;
303     fd_table[i].frozen = 0;
304     fd_table[i].opaque = q;
305     UNLOCK (fd_table_lock);
306     return 0;
307     }
308     }
309     if ( fd_table_size < 50 ) {
310     /* FIXME: We have to wait until there are no other readers of the
311     * table, i.e that the io_select is not active in another thread */
312     struct io_select_fd_s *tmp;
313    
314     tmp = realloc ( fd_table, (fd_table_size + 10) * sizeof *tmp );
315     if ( tmp ) {
316     for (i=0; i < 10; i++ )
317     tmp[fd_table_size+i].fd = -1;
318     fd_table_size += i;
319     fd_table = tmp;
320     goto again;
321     }
322     }
323    
324     UNLOCK (fd_table_lock);
325     safe_free (q);
326     /* FIXME: remove the proc table entry */
327     return mk_error (Too_Many_Procs);
328     }
329    
330    
331     void
332     _gpgme_freeze_fd ( int fd )
333     {
334     int i;
335    
336     LOCK (fd_table_lock);
337     for (i=0; i < fd_table_size; i++ ) {
338     if ( fd_table[i].fd == fd ) {
339     struct wait_item_s *q;
340    
341     fd_table[i].frozen = 1;
342     if ( (q=fd_table[i].opaque) )
343     q->frozen = 1;
344     DEBUG2 ("fd %d frozen (q=%p)", fd, q );
345     break;
346     }
347     }
348     UNLOCK (fd_table_lock);
349     }
350    
351     void
352     _gpgme_thaw_fd ( int fd )
353     {
354     int i;
355    
356     LOCK (fd_table_lock);
357     for (i=0; i < fd_table_size; i++ ) {
358     if ( fd_table[i].fd == fd ) {
359     struct wait_item_s *q;
360    
361     fd_table[i].frozen = 0;
362     if ( (q=fd_table[i].opaque) )
363     q->frozen = 0;
364     DEBUG2 ("fd %d thawed (q=%p)", fd, q );
365     break;
366     }
367     }
368     UNLOCK (fd_table_lock);
369     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26