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

Contents of /trunk/MyGPGME/wait.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Mon Apr 4 07:01:43 2005 UTC (19 years, 10 months ago) by twoaday
File MIME type: text/plain
File size: 10058 byte(s)
2005-03-22  Timo Schulz  <twoaday@freakmail.de>
                                                                                
        * editcard.c: Support new status-fd entries SC_OP_SUCCESS
        and SC_OP_FAILURE.
        * editkey.c (cmd_addrev_handler): Check if context != NULL.
        * import.c (import_command_handler): Wrong function signature.
        Noted by Kurt Fitzner.
        * types.h: Fixed encrypt_result_s. Noted by Kurt.
        * gpgme.h (gpgme_editkey_addrev_set): Changed return type.
        Kudos to Kurt.
        * key.c: Removed some unreachable code. By Kurt.
                                                                                


1 /* 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) != NULL )
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) != NULL)
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