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>
This commit is contained in:
Matt Caswell
2015-11-12 10:42:08 +00:00
parent f4511d4897
commit e8dfb5bf8e
6 changed files with 87 additions and 7 deletions

View File

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