diff options
author | Matt Caswell <matt@openssl.org> | 2015-11-12 10:42:08 +0000 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2015-11-20 23:37:17 +0000 |
commit | e8dfb5bf8e525c9799820d01b2df5fde098a9c4c (patch) | |
tree | 3f8dc36c25a36b3bf07d55cea8cccdd2a993b716 /crypto/async/async.c | |
parent | f4511d4897f56a18a2a681e2ade8063658ff2cbb (diff) |
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 <rsalz@openssl.org>
Diffstat (limited to 'crypto/async/async.c')
-rw-r--r-- | crypto/async/async.c | 34 |
1 files changed, 31 insertions, 3 deletions
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--; +} |