reap off gpg processes
authorWerner Koch <wk@gnupg.org>
Tue, 13 Feb 2001 15:00:31 +0000 (15:00 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 13 Feb 2001 15:00:31 +0000 (15:00 +0000)
trunk/gpgme/ChangeLog
trunk/gpgme/io.h
trunk/gpgme/keylist.c
trunk/gpgme/posix-io.c
trunk/gpgme/rungpg.c
trunk/gpgme/rungpg.h
trunk/gpgme/w32-io.c
trunk/gpgme/wait.c
trunk/tests/t-encrypt.c

index 076d8178abb8537735d5a4d9b1c388eca0ed79b3..7acb34c9cb19d4f365a2e6632e628e1174f59969 100644 (file)
@@ -1,5 +1,12 @@
 2001-02-13  Werner Koch  <wk@gnupg.org>
 
+       * rungpg.c (do_reaping,_gpgme_gpg_housecleaning): New.
+       (_gpgme_gpg_release): Reap children.
+       * io.h, posix-io.c (_gpgme_io_kill): New.
+       * w32-io.c (_gpgme_io_kill): New (dummy).
+
+       * keylist.c (gpgme_op_keylist_start): Cancel a pending request.
+
        * posix-io.c (_gpgme_io_read): Add some debug output. 
        (_gpgme_io_write): Ditto.
        (_gpgme_io_select): Increased the timeout.
index 14c09476e0503faae5a7ff6784e02fe2425149c3..efe2c7852a6f4d4548052fce773e1b90383a04c1 100644 (file)
@@ -51,6 +51,7 @@ int _gpgme_io_spawn ( const char *path, char **argv,
                       struct spawn_fd_item_s *fd_child_list,
                       struct spawn_fd_item_s *fd_parent_list );
 int _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal );
+int _gpgme_io_kill ( int pid, int hard );
 int _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds);
 
 
index 8b360e0069a3ead423db92a5f53675567a06142f..4e852f9700acff72ed17d4bbad7a02fcba5bb2f5 100644 (file)
@@ -347,13 +347,24 @@ finish_key ( GpgmeCtx ctx )
 
 
 
+/**
+ * gpgme_op_keylist_start:
+ * @c: context 
+ * @pattern: a GnuPg user ID or NULL for all
+ * @secret_only: List only keys where the secret part is available
+ * 
+ * Note that this function also cancels a pending key listing operaton..
+ * 
+ * Return value:  0 on success or an errorcode. 
+ **/
 GpgmeError
 gpgme_op_keylist_start ( GpgmeCtx c,  const char *pattern, int secret_only )
 {
     GpgmeError rc = 0;
     int i;
 
-    fail_on_pending_request( c );
+    if ( !c )
+        return mk_error (Invalid_Value);
     c->pending = 1;
 
     _gpgme_release_result (c);
index 4383cc6c7868c91e573946e32b1380ba7edea976..2e7e2c96364a3a76b99ee5840a70b433afccf46c 100644 (file)
@@ -206,6 +206,12 @@ _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
     return 0;
 }
 
+int
+_gpgme_io_kill ( int pid, int hard )
+{
+    return kill ( pid, hard? SIGKILL : SIGTERM );
+}
+
 
 /*
  * Select on the list of fds.
index c6c6834e06e0c5d6e49a599178bd7c37eadf807d..9b9e8ee8ed39512b175ff581593a1164583927bf 100644 (file)
@@ -37,6 +37,7 @@
 #include "rungpg.h"
 #include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
 #include "io.h"
+#include "sema.h"
 
 #include "status-table.h"
 
@@ -93,8 +94,6 @@ struct gpg_object_s {
     int pid; /* we can't use pid_t because we don't use it in Windoze */
 
     int running;
-    int exit_status;
-    int exit_signal;
     
     /* stuff needed for pipemode */
     struct {
@@ -117,7 +116,17 @@ struct gpg_object_s {
     } cmd;
 };
 
-static void kill_gpg ( GpgObject gpg );
+struct reap_s {
+    struct reap_s *next;
+    pid_t pid;
+    time_t entered;
+    int term_send;
+};
+
+static struct reap_s *reap_list;
+DEFINE_STATIC_LOCK (reap_list_lock);
+
+
 static void free_argv ( char **argv );
 static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );
 
@@ -217,25 +226,80 @@ _gpgme_gpg_release ( GpgObject gpg )
         _gpgme_io_close (gpg->colon.fd[1]);
   #endif
     free_fd_data_map (gpg->fd_data_map);
-    kill_gpg (gpg); /* fixme: should be done asyncronously */
-    xfree (gpg);
+    if (gpg->running) {
+        int pid = gpg->pid;
+        struct reap_s *r;
+
+        /* resuse the memory, so that we don't need to allocate another
+         * mem block and have to handle errors */
+        assert (sizeof *r < sizeof *gpg );
+        r = (void*)gpg;
+        memset (r, 0, sizeof *r);
+        r->pid = pid;
+        r->entered = time (NULL);
+        LOCK(reap_list_lock);
+        r->next = reap_list;
+        reap_list = r;
+        UNLOCK(reap_list_lock);
+    }
+    else
+        xfree (gpg);
 }
 
 static void
-kill_gpg ( GpgObject gpg )
+do_reaping (void)
 {
-  #if 0
-    if ( gpg->running ) {
-        /* still running? Must send a killer */
-        kill ( gpg->pid, SIGTERM);
-        sleep (2);
-        if ( !waitpid (gpg->pid, NULL, WNOHANG) ) {
-            /* pay the murderer better and then forget about it */
-            kill (gpg->pid, SIGKILL);
+    struct reap_s *r, *rlast;
+    static time_t last_check;
+    time_t cur_time = time (NULL);
+
+    /* a race does not matter here */
+    if (!last_check)
+        last_check = time(NULL);
+
+    if (last_check >= cur_time)
+        return;  /* we check only every second */
+
+    /* fixme: it would be nice if to have a TRYLOCK here */
+    LOCK (reap_list_lock);  
+    for (r=reap_list,rlast=NULL; r ; rlast=r, r=r?r->next:NULL) {
+        int dummy1, dummy2;
+
+        if ( _gpgme_io_waitpid (r->pid, 0, &dummy1, &dummy2) ) {
+            /* process has terminated - remove it from the queue */
+            void *p = r;
+            if (!rlast) {
+                reap_list = r->next;
+                r = reap_list;
+            }
+            else {
+                rlast->next = r->next;
+                r = rlast;
+            }
+            xfree (p);
+        }
+        else if ( !r->term_send ) {
+            if( r->entered+1 >= cur_time ) {
+                _gpgme_io_kill ( r->pid, 0);
+                r->term_send = 1;
+                r->entered = cur_time;
+            }
+        }
+        else {
+            /* give it 5 second before we are going to send the killer */
+            if ( r->entered+5 >= cur_time ) {
+                _gpgme_io_kill (r->pid, 1);
+                r->entered = cur_time; /* just in case we have to repat it */
+            }
         }
-        gpg->running = 0;
     }
-  #endif
+    UNLOCK (reap_list_lock);  
+}
+
+void
+_gpgme_gpg_housecleaning ()
+{
+    do_reaping ();
 }
 
 void
index bdd4a7a37ee4bae3e8c414ef96e87be8a764c2f1..e6ba4a9686708075ab580b011883156f50b6ff29 100644 (file)
@@ -95,6 +95,7 @@ typedef const char *(*GpgCommandHandler)(void*, GpgStatusCode code,
 
 GpgmeError _gpgme_gpg_new ( GpgObject *r_gpg );
 void       _gpgme_gpg_release ( GpgObject gpg );
+void       _gpgme_gpg_housecleaning (void);
 void       _gpgme_gpg_enable_pipemode ( GpgObject gpg );
 GpgmeError _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg );
 GpgmeError _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to );
index f0d31a0f282e5ee60cda07176061c4aa90e33854..92dac0a796daa8efdb74e2809faf4524a304e301 100644 (file)
@@ -598,6 +598,17 @@ _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
     return ret;
 }
 
+int
+_gpgme_io_kill ( int pid, int hard )
+{
+    HANDLE proc = fd_to_handle (pid);
+
+    #warning I am not sure how to kill a process
+    /* fixme: figure out how this can be done */
+    return 0;
+}
+
+
 
 /*
  * Select on the list of fds.
index c0cfe133621126a10ce1063b6ac36b20c9298eea..a7d137c5ede4e5590f36a76ae8e5bec9d8d9b4e1 100644 (file)
@@ -323,6 +323,7 @@ gpgme_register_idle ( void (*fnc)(void) )
 static void
 run_idle ()
 {
+    _gpgme_gpg_housecleaning ();
     if (idle_function)
         idle_function ();
 }
index 15d2197887e6ad5363ec2198e6e3053d4d380acb..86046902834de38cc9af16498eefc142b823f422 100644 (file)
@@ -64,6 +64,7 @@ main (int argc, char **argv )
   do {
     err = gpgme_new (&ctx);
     fail_if_err (err);
+    gpgme_set_armor (ctx, 1);
 
     err = gpgme_data_new_from_mem ( &in, "Hallo Leute\n", 12, 0 );
     fail_if_err (err);