From 0b6c67debf19eff094a6f3a8d2b0bf9410ae9454 Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Fri, 27 Jun 2008 16:07:33 +0000 Subject: [PATCH] 2008-06-27 Marcus Brinkmann * gpgme.texi (Cancellation): Document gpgme_cancel_async. gpgme/ 2008-06-27 Marcus Brinkmann * 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. --- trunk/doc/ChangeLog | 4 ++++ trunk/doc/gpgme.texi | 28 +++++++++++++++++++++------- trunk/gpgme/ChangeLog | 13 +++++++++++++ trunk/gpgme/context.h | 6 ++++++ trunk/gpgme/gpgme.c | 19 +++++++++++++++++++ trunk/gpgme/gpgme.h | 3 +++ trunk/gpgme/op-support.c | 3 +++ trunk/gpgme/wait-global.c | 10 ++++++++-- trunk/gpgme/wait-private.c | 8 +++++++- trunk/gpgme/wait-user.c | 10 ++++++++-- 10 files changed, 92 insertions(+), 12 deletions(-) diff --git a/trunk/doc/ChangeLog b/trunk/doc/ChangeLog index a6adbdb..8f5502a 100644 --- a/trunk/doc/ChangeLog +++ b/trunk/doc/ChangeLog @@ -1,3 +1,7 @@ +2008-06-27 Marcus Brinkmann + + * gpgme.texi (Cancellation): Document gpgme_cancel_async. + 2008-06-25 Werner Koch * gpgme.texi (Listing Keys): Updated example to the current API. diff --git a/trunk/doc/gpgme.texi b/trunk/doc/gpgme.texi index 2b96d87..50b82e2 100644 --- a/trunk/doc/gpgme.texi +++ b/trunk/doc/gpgme.texi @@ -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 ********************************************************** diff --git a/trunk/gpgme/ChangeLog b/trunk/gpgme/ChangeLog index cdda77c..198f5f7 100644 --- a/trunk/gpgme/ChangeLog +++ b/trunk/gpgme/ChangeLog @@ -1,3 +1,16 @@ +2008-06-27 Marcus Brinkmann + + * 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 * w32-util.c (_gpgme_mkstemp): Replace sprint by stpcpy. diff --git a/trunk/gpgme/context.h b/trunk/gpgme/context.h index e7e2afa..ed5d850 100644 --- a/trunk/gpgme/context.h +++ b/trunk/gpgme/context.h @@ -25,6 +25,7 @@ #include "gpgme.h" #include "engine.h" #include "wait.h" +#include "sema.h" /* 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; diff --git a/trunk/gpgme/gpgme.c b/trunk/gpgme/gpgme.c index a96db53..0f3527a 100644 --- a/trunk/gpgme/gpgme.c +++ b/trunk/gpgme/gpgme.c @@ -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); } diff --git a/trunk/gpgme/gpgme.h b/trunk/gpgme/gpgme.h index 8740469..569752f 100644 --- a/trunk/gpgme/gpgme.h +++ b/trunk/gpgme/gpgme.h @@ -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); + struct _gpgme_invalid_key { diff --git a/trunk/gpgme/op-support.c b/trunk/gpgme/op-support.c index 1212c54..fefccc6 100644 --- a/trunk/gpgme/op-support.c +++ b/trunk/gpgme/op-support.c @@ -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; diff --git a/trunk/gpgme/wait-global.c b/trunk/gpgme/wait-global.c index 3b1e3d9..97ece49 100644 --- a/trunk/gpgme/wait-global.c +++ b/trunk/gpgme/wait-global.c @@ -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, diff --git a/trunk/gpgme/wait-private.c b/trunk/gpgme/wait-private.c index 73f11b7..6633cf6 100644 --- a/trunk/gpgme/wait-private.c +++ b/trunk/gpgme/wait-private.c @@ -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, diff --git a/trunk/gpgme/wait-user.c b/trunk/gpgme/wait-user.c index 605401e..7fd61a9 100644 --- a/trunk/gpgme/wait-user.c +++ b/trunk/gpgme/wait-user.c @@ -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; -- 2.26.2