| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2016-05-18 02:24:46 +08:00
										 |  |  |  * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-05-18 02:24:46 +08:00
										 |  |  |  * Licensed under the OpenSSL license (the "License").  You may not use | 
					
						
							|  |  |  |  * this file except in compliance with the License.  You can obtain a copy | 
					
						
							|  |  |  |  * in the file LICENSE in the source distribution or at | 
					
						
							|  |  |  |  * https://www.openssl.org/source/license.html
 | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 22:48:30 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Without this we start getting longjmp crashes because it thinks we're jumping | 
					
						
							|  |  |  |  * up the stack when in fact we are jumping to an entirely different stack. The | 
					
						
							|  |  |  |  * cost of this is not having certain buffer overrun/underrun checks etc for | 
					
						
							|  |  |  |  * this source file :-( | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #undef _FORTIFY_SOURCE
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-22 09:14:43 +08:00
										 |  |  | /* This must be the first #include file */ | 
					
						
							|  |  |  | #include "async_locl.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  | #include <openssl/err.h>
 | 
					
						
							| 
									
										
										
										
											2017-08-22 20:35:43 +08:00
										 |  |  | #include "internal/cryptlib_int.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ASYNC_JOB_RUNNING   0
 | 
					
						
							|  |  |  | #define ASYNC_JOB_PAUSING   1
 | 
					
						
							|  |  |  | #define ASYNC_JOB_PAUSED    2
 | 
					
						
							|  |  |  | #define ASYNC_JOB_STOPPING  3
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  | static CRYPTO_THREAD_LOCAL ctxkey; | 
					
						
							|  |  |  | static CRYPTO_THREAD_LOCAL poolkey; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  | static void async_free_pool_internal(async_pool *pool); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  | static async_ctx *async_ctx_new(void) | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  |     async_ctx *nctx = NULL; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 02:39:34 +08:00
										 |  |  |     nctx = OPENSSL_malloc(sizeof(*nctx)); | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     if (nctx == NULL) { | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |         ASYNCerr(ASYNC_F_ASYNC_CTX_NEW, ERR_R_MALLOC_FAILURE); | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  |     async_fibre_init_dispatcher(&nctx->dispatcher); | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |     nctx->currjob = NULL; | 
					
						
							| 
									
										
										
										
											2015-11-12 18:42:08 +08:00
										 |  |  |     nctx->blocked = 0; | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     if (!CRYPTO_THREAD_set_local(&ctxkey, nctx)) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:14:36 +08:00
										 |  |  |         goto err; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return nctx; | 
					
						
							|  |  |  | err: | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     OPENSSL_free(nctx); | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  | async_ctx *async_get_ctx(void) | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-10 21:59:15 +08:00
										 |  |  |     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL)) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return (async_ctx *)CRYPTO_THREAD_get_local(&ctxkey); | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  | static int async_ctx_free(void) | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     async_ctx *ctx; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     ctx = async_get_ctx(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     if (!CRYPTO_THREAD_set_local(&ctxkey, NULL)) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:14:36 +08:00
										 |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     OPENSSL_free(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  | static ASYNC_JOB *async_job_new(void) | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     ASYNC_JOB *job = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 02:39:34 +08:00
										 |  |  |     job = OPENSSL_zalloc(sizeof(*job)); | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     if (job == NULL) { | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |         ASYNCerr(ASYNC_F_ASYNC_JOB_NEW, ERR_R_MALLOC_FAILURE); | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     job->status = ASYNC_JOB_RUNNING; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return job; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  | static void async_job_free(ASYNC_JOB *job) | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     if (job != NULL) { | 
					
						
							|  |  |  |         OPENSSL_free(job->funcargs); | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  |         async_fibre_free(&job->fibrectx); | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |         OPENSSL_free(job); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  | static ASYNC_JOB *async_get_pool_job(void) { | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |     ASYNC_JOB *job; | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     async_pool *pool; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |     if (pool == NULL) { | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |         /*
 | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |          * Pool has not been initialised, so init with the defaults, i.e. | 
					
						
							| 
									
										
										
										
											2015-10-06 17:25:21 +08:00
										 |  |  |          * no max size and no pre-created jobs | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |          */ | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  |         if (ASYNC_init_thread(0, 0) == 0) | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |             return NULL; | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |         pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     job = sk_ASYNC_JOB_pop(pool->jobs); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |     if (job == NULL) { | 
					
						
							|  |  |  |         /* Pool is empty */ | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |         if ((pool->max_size != 0) && (pool->curr_size >= pool->max_size)) | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |             return NULL; | 
					
						
							| 
									
										
										
										
											2015-09-17 00:01:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  |         job = async_job_new(); | 
					
						
							| 
									
										
										
										
											2015-11-22 09:14:43 +08:00
										 |  |  |         if (job != NULL) { | 
					
						
							|  |  |  |             if (! async_fibre_makecontext(&job->fibrectx)) { | 
					
						
							|  |  |  |                 async_job_free(job); | 
					
						
							|  |  |  |                 return NULL; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |             pool->curr_size++; | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return job; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void async_release_job(ASYNC_JOB *job) { | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     async_pool *pool; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey); | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     OPENSSL_free(job->funcargs); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |     job->funcargs = NULL; | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     sk_ASYNC_JOB_push(pool->jobs, job); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  | void async_start_func(void) | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     ASYNC_JOB *job; | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     async_ctx *ctx = async_get_ctx(); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     while (1) { | 
					
						
							|  |  |  |         /* Run the job */ | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |         job = ctx->currjob; | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |         job->ret = job->func(job->funcargs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Stop the job */ | 
					
						
							|  |  |  |         job->status = ASYNC_JOB_STOPPING; | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |         if (!async_fibre_swapcontext(&job->fibrectx, | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |                                      &ctx->dispatcher, 1)) { | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |             /*
 | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |              * Should not happen. Getting here will close the thread...can't do | 
					
						
							|  |  |  |              * much about it | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |              */ | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |             ASYNCerr(ASYNC_F_ASYNC_START_FUNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-25 23:28:57 +08:00
										 |  |  | int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret, | 
					
						
							|  |  |  |                     int (*func)(void *), void *args, size_t size) | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     async_ctx *ctx = async_get_ctx(); | 
					
						
							|  |  |  |     if (ctx == NULL) | 
					
						
							|  |  |  |         ctx = async_ctx_new(); | 
					
						
							|  |  |  |     if (ctx == NULL) { | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |         return ASYNC_ERR; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |     if (*job) { | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |         ctx->currjob = *job; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |         if (ctx->currjob != NULL) { | 
					
						
							|  |  |  |             if (ctx->currjob->status == ASYNC_JOB_STOPPING) { | 
					
						
							|  |  |  |                 *ret = ctx->currjob->ret; | 
					
						
							| 
									
										
										
										
											2016-01-25 23:28:57 +08:00
										 |  |  |                 ctx->currjob->waitctx = NULL; | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |                 async_release_job(ctx->currjob); | 
					
						
							|  |  |  |                 ctx->currjob = NULL; | 
					
						
							| 
									
										
										
										
											2015-03-26 18:15:59 +08:00
										 |  |  |                 *job = NULL; | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |                 return ASYNC_FINISH; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |             if (ctx->currjob->status == ASYNC_JOB_PAUSING) { | 
					
						
							|  |  |  |                 *job = ctx->currjob; | 
					
						
							|  |  |  |                 ctx->currjob->status = ASYNC_JOB_PAUSED; | 
					
						
							|  |  |  |                 ctx->currjob = NULL; | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |                 return ASYNC_PAUSE; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |             if (ctx->currjob->status == ASYNC_JOB_PAUSED) { | 
					
						
							|  |  |  |                 ctx->currjob = *job; | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |                 /* Resume previous job */ | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |                 if (!async_fibre_swapcontext(&ctx->dispatcher, | 
					
						
							|  |  |  |                         &ctx->currjob->fibrectx, 1)) { | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |                     ASYNCerr(ASYNC_F_ASYNC_START_JOB, | 
					
						
							|  |  |  |                              ASYNC_R_FAILED_TO_SWAP_CONTEXT); | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |                     goto err; | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Should not happen */ | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |             ASYNCerr(ASYNC_F_ASYNC_START_JOB, ERR_R_INTERNAL_ERROR); | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |             async_release_job(ctx->currjob); | 
					
						
							|  |  |  |             ctx->currjob = NULL; | 
					
						
							| 
									
										
										
										
											2015-03-26 18:15:59 +08:00
										 |  |  |             *job = NULL; | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |             return ASYNC_ERR; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |         /* Start a new job */ | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |         if ((ctx->currjob = async_get_pool_job()) == NULL) { | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |             return ASYNC_NO_JOBS; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  |         if (args != NULL) { | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |             ctx->currjob->funcargs = OPENSSL_malloc(size); | 
					
						
							|  |  |  |             if (ctx->currjob->funcargs == NULL) { | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |                 ASYNCerr(ASYNC_F_ASYNC_START_JOB, ERR_R_MALLOC_FAILURE); | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |                 async_release_job(ctx->currjob); | 
					
						
							|  |  |  |                 ctx->currjob = NULL; | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |                 return ASYNC_ERR; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |             memcpy(ctx->currjob->funcargs, args, size); | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |             ctx->currjob->funcargs = NULL; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |         ctx->currjob->func = func; | 
					
						
							| 
									
										
										
										
											2016-01-25 23:28:57 +08:00
										 |  |  |         ctx->currjob->waitctx = wctx; | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |         if (!async_fibre_swapcontext(&ctx->dispatcher, | 
					
						
							|  |  |  |                 &ctx->currjob->fibrectx, 1)) { | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |             ASYNCerr(ASYNC_F_ASYNC_START_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT); | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  |             goto err; | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 21:30:22 +08:00
										 |  |  | err: | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     async_release_job(ctx->currjob); | 
					
						
							|  |  |  |     ctx->currjob = NULL; | 
					
						
							| 
									
										
										
										
											2015-03-26 18:15:59 +08:00
										 |  |  |     *job = NULL; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |     return ASYNC_ERR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ASYNC_pause_job(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASYNC_JOB *job; | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     async_ctx *ctx = async_get_ctx(); | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     if (ctx == NULL | 
					
						
							|  |  |  |             || ctx->currjob == NULL | 
					
						
							|  |  |  |             || ctx->blocked) { | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |         /*
 | 
					
						
							| 
									
										
										
										
											2015-10-07 17:00:22 +08:00
										 |  |  |          * Could be we've deliberately not been started within a job so this is | 
					
						
							|  |  |  |          * counted as success. | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |          */ | 
					
						
							| 
									
										
										
										
											2015-10-07 17:00:22 +08:00
										 |  |  |         return 1; | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     job = ctx->currjob; | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |     job->status = ASYNC_JOB_PAUSING; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-12 18:42:08 +08:00
										 |  |  |     if (!async_fibre_swapcontext(&job->fibrectx, | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |                                  &ctx->dispatcher, 1)) { | 
					
						
							| 
									
										
										
										
											2015-10-06 21:47:00 +08:00
										 |  |  |         ASYNCerr(ASYNC_F_ASYNC_PAUSE_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT); | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-25 23:28:57 +08:00
										 |  |  |     /* Reset counts of added and deleted fds */ | 
					
						
							|  |  |  |     async_wait_ctx_reset_counts(job->waitctx); | 
					
						
							| 
									
										
										
										
											2015-09-16 19:28:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  | static void async_empty_pool(async_pool *pool) | 
					
						
							| 
									
										
										
										
											2015-09-17 06:43:45 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     ASYNC_JOB *job; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     if (!pool || !pool->jobs) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 06:43:45 +08:00
										 |  |  |     do { | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |         job = sk_ASYNC_JOB_pop(pool->jobs); | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  |         async_job_free(job); | 
					
						
							| 
									
										
										
										
											2015-09-17 06:43:45 +08:00
										 |  |  |     } while (job); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  | int async_init(void) | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     if (!CRYPTO_THREAD_init_local(&ctxkey, NULL)) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CRYPTO_THREAD_init_local(&poolkey, NULL)) { | 
					
						
							|  |  |  |         CRYPTO_THREAD_cleanup_local(&ctxkey); | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  | void async_deinit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CRYPTO_THREAD_cleanup_local(&ctxkey); | 
					
						
							|  |  |  |     CRYPTO_THREAD_cleanup_local(&poolkey); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  | int ASYNC_init_thread(size_t max_size, size_t init_size) | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     async_pool *pool; | 
					
						
							| 
									
										
										
										
											2015-09-17 00:01:58 +08:00
										 |  |  |     size_t curr_size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  |     if (init_size > max_size) { | 
					
						
							|  |  |  |         ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ASYNC_R_INVALID_POOL_SIZE); | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-10 21:59:15 +08:00
										 |  |  |     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL)) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_ASYNC)) { | 
					
						
							| 
									
										
										
										
											2015-11-20 05:44:13 +08:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 02:39:34 +08:00
										 |  |  |     pool = OPENSSL_zalloc(sizeof(*pool)); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |     if (pool == NULL) { | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  |         ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ERR_R_MALLOC_FAILURE); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 01:56:14 +08:00
										 |  |  |     pool->jobs = sk_ASYNC_JOB_new_reserve(NULL, init_size); | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     if (pool->jobs == NULL) { | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  |         ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ERR_R_MALLOC_FAILURE); | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |         OPENSSL_free(pool); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pool->max_size = max_size; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |     /* Pre-create jobs as required */ | 
					
						
							| 
									
										
										
										
											2015-11-22 09:14:43 +08:00
										 |  |  |     while (init_size--) { | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |         ASYNC_JOB *job; | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  |         job = async_job_new(); | 
					
						
							| 
									
										
										
										
											2015-11-22 09:14:43 +08:00
										 |  |  |         if (job == NULL || !async_fibre_makecontext(&job->fibrectx)) { | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |             /*
 | 
					
						
							| 
									
										
										
										
											2015-11-22 09:14:43 +08:00
										 |  |  |              * Not actually fatal because we already created the pool, just | 
					
						
							|  |  |  |              * skip creation of any more jobs | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |              */ | 
					
						
							| 
									
										
										
										
											2015-11-22 09:14:43 +08:00
										 |  |  |             async_job_free(job); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-11-22 09:14:43 +08:00
										 |  |  |         job->funcargs = NULL; | 
					
						
							| 
									
										
										
										
											2017-09-19 06:48:14 +08:00
										 |  |  |         sk_ASYNC_JOB_push(pool->jobs, job); /* Cannot fail due to reserve */ | 
					
						
							| 
									
										
										
										
											2015-11-22 09:14:43 +08:00
										 |  |  |         curr_size++; | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     pool->curr_size = curr_size; | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     if (!CRYPTO_THREAD_set_local(&poolkey, pool)) { | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  |         ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ASYNC_R_FAILED_TO_SET_POOL); | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |         goto err; | 
					
						
							| 
									
										
										
										
											2015-09-17 06:43:45 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-09-17 00:01:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  | err: | 
					
						
							|  |  |  |     async_free_pool_internal(pool); | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  | static void async_free_pool_internal(async_pool *pool) | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-09-17 00:01:58 +08:00
										 |  |  |     if (pool == NULL) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2015-09-17 06:43:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     async_empty_pool(pool); | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  |     sk_ASYNC_JOB_free(pool->jobs); | 
					
						
							|  |  |  |     OPENSSL_free(pool); | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     CRYPTO_THREAD_set_local(&poolkey, NULL); | 
					
						
							| 
									
										
										
										
											2015-11-20 05:44:13 +08:00
										 |  |  |     async_local_cleanup(); | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  |     async_ctx_free(); | 
					
						
							| 
									
										
										
										
											2015-07-23 00:50:51 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-24 15:15:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-14 07:54:44 +08:00
										 |  |  | void ASYNC_cleanup_thread(void) | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-03-03 00:15:52 +08:00
										 |  |  |     async_free_pool_internal((async_pool *)CRYPTO_THREAD_get_local(&poolkey)); | 
					
						
							| 
									
										
										
										
											2015-11-13 23:21:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-24 15:15:31 +08:00
										 |  |  | ASYNC_JOB *ASYNC_get_current_job(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-10-06 18:25:16 +08:00
										 |  |  |     async_ctx *ctx; | 
					
						
							| 
									
										
										
										
											2015-11-12 19:50:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ctx = async_get_ctx(); | 
					
						
							| 
									
										
										
										
											2016-06-29 06:18:50 +08:00
										 |  |  |     if (ctx == NULL) | 
					
						
							| 
									
										
										
										
											2015-07-24 15:15:31 +08:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ctx->currjob; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-25 23:28:57 +08:00
										 |  |  | ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job) | 
					
						
							| 
									
										
										
										
											2015-07-24 15:15:31 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-01-25 23:28:57 +08:00
										 |  |  |     return job->waitctx; | 
					
						
							| 
									
										
										
										
											2015-07-24 15:15:31 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-11-12 18:42:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | void ASYNC_block_pause(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     async_ctx *ctx = async_get_ctx(); | 
					
						
							|  |  |  |     if (ctx == NULL || ctx->currjob == NULL) { | 
					
						
							| 
									
										
										
										
											2015-11-12 18:42:08 +08:00
										 |  |  |         /*
 | 
					
						
							|  |  |  |          * We're not in a job anyway so ignore this | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     ctx->blocked++; | 
					
						
							| 
									
										
										
										
											2015-11-12 18:42:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASYNC_unblock_pause(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |     async_ctx *ctx = async_get_ctx(); | 
					
						
							|  |  |  |     if (ctx == NULL || ctx->currjob == NULL) { | 
					
						
							| 
									
										
										
										
											2015-11-12 18:42:08 +08:00
										 |  |  |         /*
 | 
					
						
							|  |  |  |          * We're not in a job anyway so ignore this | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-29 06:18:50 +08:00
										 |  |  |     if (ctx->blocked > 0) | 
					
						
							| 
									
										
										
										
											2016-02-09 00:43:03 +08:00
										 |  |  |         ctx->blocked--; | 
					
						
							| 
									
										
										
										
											2015-11-12 18:42:08 +08:00
										 |  |  | } |