From e8dfb5bf8e525c9799820d01b2df5fde098a9c4c Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 12 Nov 2015 10:42:08 +0000 Subject: Add ASYNC_block_pause and ASYNC_unblock_pause There are potential deadlock situations that can occur if code executing within the context of a job aquires a lock, and then pauses the job. This adds an ability to temporarily block pauses from occuring whilst performing work and holding a lock. Reviewed-by: Rich Salz --- crypto/async/async.c | 34 +++++++++++++++++++++++++++++++--- crypto/async/async_locl.h | 1 + 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'crypto') diff --git a/crypto/async/async.c b/crypto/async/async.c index d08ac132b7..9b9963fb5e 100644 --- a/crypto/async/async.c +++ b/crypto/async/async.c @@ -80,6 +80,7 @@ static async_ctx *async_ctx_new(void) async_fibre_init_dispatcher(&nctx->dispatcher); nctx->currjob = NULL; + nctx->blocked = 0; if(!async_set_ctx(nctx)) goto err; @@ -286,7 +287,9 @@ int ASYNC_pause_job(void) { ASYNC_JOB *job; - if(!async_get_ctx() || !async_get_ctx()->currjob) { + if (async_get_ctx() == NULL + || async_get_ctx()->currjob == NULL + || async_get_ctx()->blocked) { /* * Could be we've deliberately not been started within a job so this is * counted as success. @@ -297,8 +300,8 @@ int ASYNC_pause_job(void) job = async_get_ctx()->currjob; job->status = ASYNC_JOB_PAUSING; - if(!async_fibre_swapcontext(&job->fibrectx, - &async_get_ctx()->dispatcher, 1)) { + if (!async_fibre_swapcontext(&job->fibrectx, + &async_get_ctx()->dispatcher, 1)) { ASYNCerr(ASYNC_F_ASYNC_PAUSE_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT); return 0; } @@ -405,3 +408,28 @@ void ASYNC_clear_wake(ASYNC_JOB *job) async_read1(job->wait_fd, &dummy); job->wake_set = 0; } + +void ASYNC_block_pause(void) +{ + if (async_get_ctx() == NULL + || async_get_ctx()->currjob == NULL) { + /* + * We're not in a job anyway so ignore this + */ + return; + } + async_get_ctx()->blocked++; +} + +void ASYNC_unblock_pause(void) +{ + if (async_get_ctx() == NULL + || async_get_ctx()->currjob == NULL) { + /* + * We're not in a job anyway so ignore this + */ + return; + } + if(async_get_ctx()->blocked > 0) + async_get_ctx()->blocked--; +} diff --git a/crypto/async/async_locl.h b/crypto/async/async_locl.h index 90c0db56a3..ba329788b3 100644 --- a/crypto/async/async_locl.h +++ b/crypto/async/async_locl.h @@ -63,6 +63,7 @@ typedef struct async_ctx_st async_ctx; struct async_ctx_st { async_fibre dispatcher; ASYNC_JOB *currjob; + unsigned int blocked; }; struct async_job_st { -- cgit v1.2.3