summaryrefslogtreecommitdiffstats
path: root/crypto/async/async.c
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2015-11-12 10:42:08 +0000
committerMatt Caswell <matt@openssl.org>2015-11-20 23:37:17 +0000
commite8dfb5bf8e525c9799820d01b2df5fde098a9c4c (patch)
tree3f8dc36c25a36b3bf07d55cea8cccdd2a993b716 /crypto/async/async.c
parentf4511d4897f56a18a2a681e2ade8063658ff2cbb (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.c34
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--;
+}