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

* 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.
This commit is contained in:
Marcus Brinkmann 2008-06-27 16:07:33 +00:00
parent eccdb17c30
commit 695ec56ffb
10 changed files with 92 additions and 12 deletions

View 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.

View 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 **********************************************************

View 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.

View File

@ -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;

View 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);
}

View 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);
struct _gpgme_invalid_key
{

View 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;

View 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,

View 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,

View 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;