2008-06-27 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Fri, 27 Jun 2008 16:07:33 +0000 (16:07 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Fri, 27 Jun 2008 16:07:33 +0000 (16:07 +0000)
* gpgme.texi (Cancellation): Document gpgme_cancel_async.

gpgme/
2008-06-27  Marcus Brinkmann  <marcus@g10code.de>

* context.h: Include "sema.h".
(struct gpgme_context): New members lock and canceled.
* gpgme.c (gpgme_new): Initialize lock.
(gpgme_release): Destroy lock.
(gpgme_cancel_async): New function.
* op-support.c (_gpgme_op_reset): Reset the canceled flag.
* wait-global.c (gpgme_wait): Check cancel flag before processing
any I/O callbacks.
* wait-private.c (_gpgme_wait_on_condition): Likewise.
* wait-user.c (_gpgme_user_io_cb_handler): Likewise.

doc/ChangeLog
doc/gpgme.texi
gpgme/ChangeLog
gpgme/context.h
gpgme/gpgme.c
gpgme/gpgme.h
gpgme/op-support.c
gpgme/wait-global.c
gpgme/wait-private.c
gpgme/wait-user.c

index a6adbdb6e62d0bb7bedb8f4fac4e5a8668b05332..8f5502a7967ecc5c8a6daa92d2dc93df58ba18d4 100644 (file)
@@ -1,3 +1,7 @@
+2008-06-27  Marcus Brinkmann  <marcus@g10code.de>
+
+       * gpgme.texi (Cancellation): Document gpgme_cancel_async.
+
 2008-06-25  Werner Koch  <wk@g10code.com>
 
        * gpgme.texi (Listing Keys): Updated example to the current API.
index 2b96d873c3683e513fd3f13782c04850b5ed06e9..50b82e236c900418194e6e12068d7bd0c5272535 100644 (file)
@@ -5488,13 +5488,15 @@ private:
 @cindex aborting operations
 @cindex cancelling operations
 
-Sometimes you do not want to wait for an operation to finish.  If you
-use external I/O callbacks, you can cancel a pending operation.
-However, you must ensure that no other thread is currently using the
-context in which the operation you want to cancel runs.  This includes
-callback handlers.  So your external event loop must either be halted
-or otherwise it must be guaranteed that no installed I/O callbacks are
-run for this context.
+Sometimes you do not want to wait for an operation to finish.
+@acronym{GPGME} provides two different functions to achieve that.  The
+function @code{gpgme_cancel} takes effect immediately.  When it
+returns, the operation is effectively canceled.  However, it has some
+limitations and can not be used with synchronous operations.  In
+contrast, the function @code{gpgme_cancel_async} can be used with any
+context and from any thread, but it is not guaranteed to take effect
+immediately.  Instead, cancellation occurs at the next possible time
+(typically the next time I/O occurs in the target context).
 
 @deftypefun gpgme_ctx_t gpgme_cancel (@w{gpgme_ctx_t @var{ctx}})
 The function @code{gpgme_cancel} attempts to cancel a pending
@@ -5517,6 +5519,18 @@ The function returns an error code if the cancellation failed (in this
 case the state of @var{ctx} is not modified).
 @end deftypefun
 
+
+@deftypefun gpgme_ctx_t gpgme_cancel_async (@w{gpgme_ctx_t @var{ctx}})
+The function @code{gpgme_cancel} attempts to cancel a pending
+operation in the context @var{ctx}.  This can be called by any thread
+at any time after starting an operation on the context, but will not
+take effect immediately.  The actual cancellation happens at the next
+time GPGME processes I/O in that context.
+
+The function returns an error code if the cancellation failed (in this
+case the state of @var{ctx} is not modified).
+@end deftypefun
+
 @c **********************************************************
 @c *******************  Appendices  *************************
 @c **********************************************************
index cdda77ca293ec55ae17e6ece5390d5f52edd74bf..198f5f77f5dca480390aae44be4a39be3f494d93 100644 (file)
@@ -1,3 +1,16 @@
+2008-06-27  Marcus Brinkmann  <marcus@g10code.de>
+
+       * context.h: Include "sema.h".
+       (struct gpgme_context): New members lock and canceled.
+       * gpgme.c (gpgme_new): Initialize lock.
+       (gpgme_release): Destroy lock.
+       (gpgme_cancel_async): New function.
+       * op-support.c (_gpgme_op_reset): Reset the canceled flag.
+       * wait-global.c (gpgme_wait): Check cancel flag before processing
+       any I/O callbacks.
+       * wait-private.c (_gpgme_wait_on_condition): Likewise.
+       * wait-user.c (_gpgme_user_io_cb_handler): Likewise.
+
 2008-06-26  Werner Koch  <wk@g10code.com>
 
        * w32-util.c (_gpgme_mkstemp): Replace sprint by stpcpy.
index e7e2afa44fd2c5f9e0d29e5883b9636b6e37d642..ed5d850211121ee9ef0147ac7875f3d210affe6a 100644 (file)
@@ -25,6 +25,7 @@
 #include "gpgme.h"
 #include "engine.h"
 #include "wait.h"
+#include "sema.h"
 
 \f
 /* Operations might require to remember arbitrary information and data
@@ -63,6 +64,11 @@ typedef struct ctx_op_data *ctx_op_data_t;
    be performed (sequentially).  */
 struct gpgme_context
 {
+  DECLARE_LOCK (lock);
+
+  /* True if the context was canceled asynchronously.  */
+  int canceled;
+
   /* The engine info for this context.  */
   gpgme_engine_info_t engine_info;
 
index a96db530bb9b693c6235a18b5dc31201f8e54e3b..0f3527a44a50e33e523a1f7bff4028f56a7e3b69 100644 (file)
@@ -54,6 +54,8 @@ gpgme_new (gpgme_ctx_t *r_ctx)
   if (!ctx)
     return TRACE_ERR (gpg_error_from_errno (errno));
 
+  INIT_LOCK (ctx->lock);
+  
   _gpgme_engine_info_copy (&ctx->engine_info);
   if (!ctx->engine_info)
     {
@@ -121,6 +123,22 @@ gpgme_cancel (gpgme_ctx_t ctx)
   return TRACE_ERR (0);
 }
 
+
+/* Cancel a pending operation asynchronously.  */
+gpgme_error_t
+gpgme_cancel_async (gpgme_ctx_t ctx)
+{
+  gpgme_error_t err;
+  TRACE_BEG (DEBUG_CTX, "gpgme_cancel_async", ctx);
+
+  LOCK (ctx->lock);
+  ctx->canceled = 1;
+  UNLOCK (ctx->lock);
+
+  return TRACE_ERR (0);
+}
+
+
 /* Release all resources associated with the given context.  */
 void
 gpgme_release (gpgme_ctx_t ctx)
@@ -139,6 +157,7 @@ gpgme_release (gpgme_ctx_t ctx)
   if (ctx->lc_messages)
     free (ctx->lc_messages);
   _gpgme_engine_info_release (ctx->engine_info);
+  DESTROY_LOCK (ctx->lock);
   free (ctx);
 }
 
index 8740469fd67818079508998123eaf5c399b20dd1..569752fd6be5c42865cfdc69f4874bdb76cec8ff 100644 (file)
@@ -1120,6 +1120,9 @@ unsigned long gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx,
 /* Cancel a pending asynchronous operation.  */
 gpgme_error_t gpgme_cancel (gpgme_ctx_t ctx);
 
+/* Cancel a pending operation asynchronously.  */
+gpgme_error_t gpgme_cancel_async (gpgme_ctx_t ctx);
+
 \f
 struct _gpgme_invalid_key
 {
index 1212c542f5b07d4e822e79c08f1f2a5ec0826a8b..fefccc67b345e2ff3edf53ca2e56409b2f35c398 100644 (file)
@@ -76,6 +76,9 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
   type &= 255;
 
   _gpgme_release_result (ctx);
+  LOCK (ctx->lock);
+  ctx->canceled = 0;
+  UNLOCK (ctx->lock);
 
   if (ctx->engine && no_reset)
     reuse_engine = 1;
index 3b1e3d9af8e0f4826307e842640da7ea527a1a7c..97ece4992c24de043f9a2594f00c683a206fd186 100644 (file)
@@ -299,7 +299,7 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)
          if (fdt.fds[i].fd != -1 && fdt.fds[i].signaled)
            {
              gpgme_ctx_t ictx;
-             gpgme_error_t err;
+             gpgme_error_t err = 0;
              struct wait_item_s *item;
              
              assert (nr);
@@ -310,7 +310,13 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)
              ictx = item->ctx;
              assert (ictx);
 
-             err = _gpgme_run_io_cb (&fdt.fds[i], 0);
+             LOCK (ctx->lock);
+             if (ctx->canceled)
+               err = gpg_error (GPG_ERR_CANCELED);
+             UNLOCK (ctx->lock);
+
+             if (!err)
+               err = _gpgme_run_io_cb (&fdt.fds[i], 0);
              if (err)
                {
                  /* An error occured.  Close all fds in this context,
index 73f11b760aa2f415355c5959fdc2d6f1d7cf9c2f..6633cf67f14088eb4363849ee9722afce917b3ef 100644 (file)
@@ -105,7 +105,13 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)
              assert (nr);
              nr--;
 
-             err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0);
+             LOCK (ctx->lock);
+             if (ctx->canceled)
+               err = gpg_error (GPG_ERR_CANCELED);
+             UNLOCK (ctx->lock);
+             
+             if (!err)
+               err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0);
              if (err)
                {
                  /* An error occured.  Close all fds in this context,
index 605401e936f0adf6b3b4f2054f45a429dfd1fd11..7fd61a9b3e5e22cf6eac2bb8869f25832d90a3c5 100644 (file)
@@ -39,7 +39,7 @@
 gpgme_error_t
 _gpgme_user_io_cb_handler (void *data, int fd)
 {
-  gpgme_error_t err;
+  gpgme_error_t err = 0;
   struct tag *tag = (struct tag *) data;
   gpgme_ctx_t ctx;
 
@@ -47,7 +47,13 @@ _gpgme_user_io_cb_handler (void *data, int fd)
   ctx = tag->ctx;
   assert (ctx);
 
-  err = _gpgme_run_io_cb (&ctx->fdt.fds[tag->idx], 0);
+  LOCK (ctx->lock);
+  if (ctx->canceled)
+    err = gpg_error (GPG_ERR_CANCELED);
+  UNLOCK (ctx->lock);
+
+  if (! err)
+    err = _gpgme_run_io_cb (&ctx->fdt.fds[tag->idx], 0);
   if (err)
     {
       unsigned int idx;