diff options
author | Matt Caswell <matt@openssl.org> | 2015-07-22 17:50:51 +0100 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2015-11-20 23:33:46 +0000 |
commit | 252d6d3aa62dccf0dc826644b7da0b6bafa3831b (patch) | |
tree | 529055a0ca2eb9f6564f18e4a87d25d1d458c371 /crypto | |
parent | 7070e5ca2fa41940d56599bf016a45cb1c0e03f0 (diff) |
Add ASYNC_JOB pools
It is expensive to create the ASYNC_JOB objects due to the "makecontext"
call. This change adds support for pools of ASYNC_JOB objects so that we
don't have to create a new ASYNC_JOB every time we want to use one.
Reviewed-by: Rich Salz <rsalz@openssl.org>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/async/async.c | 126 |
1 files changed, 107 insertions, 19 deletions
diff --git a/crypto/async/async.c b/crypto/async/async.c index c0f362e2c8..6fed1979f9 100644 --- a/crypto/async/async.c +++ b/crypto/async/async.c @@ -61,6 +61,12 @@ #define ASYNC_JOB_PAUSED 2 #define ASYNC_JOB_STOPPING 3 +static size_t pool_max_size = 0; +static size_t curr_size = 0; + +DECLARE_STACK_OF(ASYNC_JOB) +static STACK_OF(ASYNC_JOB) *pool = NULL; + static ASYNC_CTX *ASYNC_CTX_new(void) { @@ -121,22 +127,60 @@ static void ASYNC_JOB_free(ASYNC_JOB *job) } } -void ASYNC_start_func(void) -{ +static ASYNC_JOB *async_get_pool_job(void) { ASYNC_JOB *job; - /* Run the job */ - job = ASYNC_get_ctx()->currjob; - job->ret = job->func(job->funcargs); - - /* Stop the job */ - job->status = ASYNC_JOB_STOPPING; - if(!ASYNC_FIBRE_swapcontext(&job->fibrectx, - &ASYNC_get_ctx()->dispatcher, 0)) { + if (pool == NULL) { /* - * Should not happen. Getting here will close the thread...can't do much - * about it + * Pool has not been initialised, so init with the defaults, i.e. + * global pool, with no max size and no pre-created jobs */ + if (ASYNC_init_pool(0, 0, 0) == 0) + return NULL; + } + + job = sk_ASYNC_JOB_pop(pool); + if (job == NULL) { + /* Pool is empty */ + if (pool_max_size && curr_size >= pool_max_size) { + /* Pool is at max size. We cannot continue */ + return NULL; + } + job = ASYNC_JOB_new(); + if (job) { + ASYNC_FIBRE_makecontext(&job->fibrectx); + curr_size++; + } + } + return job; +} + +static void async_release_job(ASYNC_JOB *job) { + if(job->funcargs) + OPENSSL_free(job->funcargs); + job->funcargs = NULL; + /* Ignore error return */ + sk_ASYNC_JOB_push(pool, job); +} + +void ASYNC_start_func(void) +{ + ASYNC_JOB *job; + + while (1) { + /* Run the job */ + job = ASYNC_get_ctx()->currjob; + job->ret = job->func(job->funcargs); + + /* Stop the job */ + job->status = ASYNC_JOB_STOPPING; + if(!ASYNC_FIBRE_swapcontext(&job->fibrectx, + &ASYNC_get_ctx()->dispatcher, 1)) { + /* + * Should not happen. Getting here will close the thread...can't do much + * about it + */ + } } } @@ -155,7 +199,7 @@ int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *), if(ASYNC_get_ctx()->currjob) { if(ASYNC_get_ctx()->currjob->status == ASYNC_JOB_STOPPING) { *ret = ASYNC_get_ctx()->currjob->ret; - ASYNC_JOB_free(ASYNC_get_ctx()->currjob); + async_release_job(ASYNC_get_ctx()->currjob); ASYNC_get_ctx()->currjob = NULL; *job = NULL; ASYNC_CTX_free(); @@ -179,7 +223,7 @@ int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *), } /* Should not happen */ - ASYNC_JOB_free(ASYNC_get_ctx()->currjob); + async_release_job(ASYNC_get_ctx()->currjob); ASYNC_get_ctx()->currjob = NULL; *job = NULL; ASYNC_CTX_free(); @@ -187,15 +231,15 @@ int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *), } /* Start a new job */ - if(!(ASYNC_get_ctx()->currjob = ASYNC_JOB_new())) { + if(!(ASYNC_get_ctx()->currjob = async_get_pool_job())) { ASYNC_CTX_free(); - return ASYNC_ERR; + return ASYNC_NO_JOBS; } if(args != NULL) { ASYNC_get_ctx()->currjob->funcargs = OPENSSL_malloc(size); if(!ASYNC_get_ctx()->currjob->funcargs) { - ASYNC_JOB_free(ASYNC_get_ctx()->currjob); + async_release_job(ASYNC_get_ctx()->currjob); ASYNC_get_ctx()->currjob = NULL; ASYNC_CTX_free(); return ASYNC_ERR; @@ -206,14 +250,13 @@ int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *), } ASYNC_get_ctx()->currjob->func = func; - ASYNC_FIBRE_makecontext(&ASYNC_get_ctx()->currjob->fibrectx); if(!ASYNC_FIBRE_swapcontext(&ASYNC_get_ctx()->dispatcher, &ASYNC_get_ctx()->currjob->fibrectx, 1)) goto err; } err: - ASYNC_JOB_free(ASYNC_get_ctx()->currjob); + async_release_job(ASYNC_get_ctx()->currjob); ASYNC_get_ctx()->currjob = NULL; *job = NULL; ASYNC_CTX_free(); @@ -247,3 +290,48 @@ int ASYNC_in_job(void) return 0; } + +int ASYNC_init_pool(unsigned int local, size_t max_size, size_t init_size) +{ + if (local != 0) { + /* We only support a global pool so far */ + return 0; + } + + pool_max_size = max_size; + pool = sk_ASYNC_JOB_new_null(); + if (pool == NULL) { + return 0; + } + /* Pre-create jobs as required */ + while (init_size) { + ASYNC_JOB *job; + job = ASYNC_JOB_new(); + if (job) { + ASYNC_FIBRE_makecontext(&job->fibrectx); + job->funcargs = NULL; + sk_ASYNC_JOB_push(pool, job); + curr_size++; + init_size--; + } else { + /* + * Not actually fatal because we already created the pool, just skip + * creation of any more jobs + */ + init_size = 0; + } + } + + return 1; +} + +void ASYNC_free_pool(void) +{ + ASYNC_JOB *job; + + do { + job = sk_ASYNC_JOB_pop(pool); + ASYNC_JOB_free(job); + } while (job); + sk_ASYNC_JOB_free(pool); +} |