xref: /freebsd/crypto/openssl/crypto/async/async.c (revision b077aed3)
1e71b7053SJung-uk Kim /*
2*b077aed3SPierre Pronchery  * Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim  *
4*b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
8e71b7053SJung-uk Kim  */
9e71b7053SJung-uk Kim 
10e71b7053SJung-uk Kim /*
11e71b7053SJung-uk Kim  * Without this we start getting longjmp crashes because it thinks we're jumping
12e71b7053SJung-uk Kim  * up the stack when in fact we are jumping to an entirely different stack. The
13e71b7053SJung-uk Kim  * cost of this is not having certain buffer overrun/underrun checks etc for
14e71b7053SJung-uk Kim  * this source file :-(
15e71b7053SJung-uk Kim  */
16e71b7053SJung-uk Kim #undef _FORTIFY_SOURCE
17e71b7053SJung-uk Kim 
18e71b7053SJung-uk Kim /* This must be the first #include file */
1917f01e99SJung-uk Kim #include "async_local.h"
20e71b7053SJung-uk Kim 
21e71b7053SJung-uk Kim #include <openssl/err.h>
2217f01e99SJung-uk Kim #include "crypto/cryptlib.h"
23e71b7053SJung-uk Kim #include <string.h>
24e71b7053SJung-uk Kim 
25e71b7053SJung-uk Kim #define ASYNC_JOB_RUNNING   0
26e71b7053SJung-uk Kim #define ASYNC_JOB_PAUSING   1
27e71b7053SJung-uk Kim #define ASYNC_JOB_PAUSED    2
28e71b7053SJung-uk Kim #define ASYNC_JOB_STOPPING  3
29e71b7053SJung-uk Kim 
30e71b7053SJung-uk Kim static CRYPTO_THREAD_LOCAL ctxkey;
31e71b7053SJung-uk Kim static CRYPTO_THREAD_LOCAL poolkey;
32e71b7053SJung-uk Kim 
33*b077aed3SPierre Pronchery static void async_delete_thread_state(void *arg);
34*b077aed3SPierre Pronchery 
async_ctx_new(void)35e71b7053SJung-uk Kim static async_ctx *async_ctx_new(void)
36e71b7053SJung-uk Kim {
37e71b7053SJung-uk Kim     async_ctx *nctx;
38e71b7053SJung-uk Kim 
39*b077aed3SPierre Pronchery     if (!ossl_init_thread_start(NULL, NULL, async_delete_thread_state))
40e71b7053SJung-uk Kim         return NULL;
41e71b7053SJung-uk Kim 
42e71b7053SJung-uk Kim     nctx = OPENSSL_malloc(sizeof(*nctx));
43e71b7053SJung-uk Kim     if (nctx == NULL) {
44*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ERR_R_MALLOC_FAILURE);
45e71b7053SJung-uk Kim         goto err;
46e71b7053SJung-uk Kim     }
47e71b7053SJung-uk Kim 
48e71b7053SJung-uk Kim     async_fibre_init_dispatcher(&nctx->dispatcher);
49e71b7053SJung-uk Kim     nctx->currjob = NULL;
50e71b7053SJung-uk Kim     nctx->blocked = 0;
51e71b7053SJung-uk Kim     if (!CRYPTO_THREAD_set_local(&ctxkey, nctx))
52e71b7053SJung-uk Kim         goto err;
53e71b7053SJung-uk Kim 
54e71b7053SJung-uk Kim     return nctx;
55e71b7053SJung-uk Kim err:
56e71b7053SJung-uk Kim     OPENSSL_free(nctx);
57e71b7053SJung-uk Kim 
58e71b7053SJung-uk Kim     return NULL;
59e71b7053SJung-uk Kim }
60e71b7053SJung-uk Kim 
async_get_ctx(void)61e71b7053SJung-uk Kim async_ctx *async_get_ctx(void)
62e71b7053SJung-uk Kim {
63e71b7053SJung-uk Kim     return (async_ctx *)CRYPTO_THREAD_get_local(&ctxkey);
64e71b7053SJung-uk Kim }
65e71b7053SJung-uk Kim 
async_ctx_free(void)66e71b7053SJung-uk Kim static int async_ctx_free(void)
67e71b7053SJung-uk Kim {
68e71b7053SJung-uk Kim     async_ctx *ctx;
69e71b7053SJung-uk Kim 
70e71b7053SJung-uk Kim     ctx = async_get_ctx();
71e71b7053SJung-uk Kim 
72e71b7053SJung-uk Kim     if (!CRYPTO_THREAD_set_local(&ctxkey, NULL))
73e71b7053SJung-uk Kim         return 0;
74e71b7053SJung-uk Kim 
75e71b7053SJung-uk Kim     OPENSSL_free(ctx);
76e71b7053SJung-uk Kim 
77e71b7053SJung-uk Kim     return 1;
78e71b7053SJung-uk Kim }
79e71b7053SJung-uk Kim 
async_job_new(void)80e71b7053SJung-uk Kim static ASYNC_JOB *async_job_new(void)
81e71b7053SJung-uk Kim {
82e71b7053SJung-uk Kim     ASYNC_JOB *job = NULL;
83e71b7053SJung-uk Kim 
84e71b7053SJung-uk Kim     job = OPENSSL_zalloc(sizeof(*job));
85e71b7053SJung-uk Kim     if (job == NULL) {
86*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ERR_R_MALLOC_FAILURE);
87e71b7053SJung-uk Kim         return NULL;
88e71b7053SJung-uk Kim     }
89e71b7053SJung-uk Kim 
90e71b7053SJung-uk Kim     job->status = ASYNC_JOB_RUNNING;
91e71b7053SJung-uk Kim 
92e71b7053SJung-uk Kim     return job;
93e71b7053SJung-uk Kim }
94e71b7053SJung-uk Kim 
async_job_free(ASYNC_JOB * job)95e71b7053SJung-uk Kim static void async_job_free(ASYNC_JOB *job)
96e71b7053SJung-uk Kim {
97e71b7053SJung-uk Kim     if (job != NULL) {
98e71b7053SJung-uk Kim         OPENSSL_free(job->funcargs);
99e71b7053SJung-uk Kim         async_fibre_free(&job->fibrectx);
100e71b7053SJung-uk Kim         OPENSSL_free(job);
101e71b7053SJung-uk Kim     }
102e71b7053SJung-uk Kim }
103e71b7053SJung-uk Kim 
async_get_pool_job(void)104e71b7053SJung-uk Kim static ASYNC_JOB *async_get_pool_job(void) {
105e71b7053SJung-uk Kim     ASYNC_JOB *job;
106e71b7053SJung-uk Kim     async_pool *pool;
107e71b7053SJung-uk Kim 
108e71b7053SJung-uk Kim     pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey);
109e71b7053SJung-uk Kim     if (pool == NULL) {
110e71b7053SJung-uk Kim         /*
111e71b7053SJung-uk Kim          * Pool has not been initialised, so init with the defaults, i.e.
112e71b7053SJung-uk Kim          * no max size and no pre-created jobs
113e71b7053SJung-uk Kim          */
114e71b7053SJung-uk Kim         if (ASYNC_init_thread(0, 0) == 0)
115e71b7053SJung-uk Kim             return NULL;
116e71b7053SJung-uk Kim         pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey);
117e71b7053SJung-uk Kim     }
118e71b7053SJung-uk Kim 
119e71b7053SJung-uk Kim     job = sk_ASYNC_JOB_pop(pool->jobs);
120e71b7053SJung-uk Kim     if (job == NULL) {
121e71b7053SJung-uk Kim         /* Pool is empty */
122e71b7053SJung-uk Kim         if ((pool->max_size != 0) && (pool->curr_size >= pool->max_size))
123e71b7053SJung-uk Kim             return NULL;
124e71b7053SJung-uk Kim 
125e71b7053SJung-uk Kim         job = async_job_new();
126e71b7053SJung-uk Kim         if (job != NULL) {
127e71b7053SJung-uk Kim             if (! async_fibre_makecontext(&job->fibrectx)) {
128e71b7053SJung-uk Kim                 async_job_free(job);
129e71b7053SJung-uk Kim                 return NULL;
130e71b7053SJung-uk Kim             }
131e71b7053SJung-uk Kim             pool->curr_size++;
132e71b7053SJung-uk Kim         }
133e71b7053SJung-uk Kim     }
134e71b7053SJung-uk Kim     return job;
135e71b7053SJung-uk Kim }
136e71b7053SJung-uk Kim 
async_release_job(ASYNC_JOB * job)137e71b7053SJung-uk Kim static void async_release_job(ASYNC_JOB *job) {
138e71b7053SJung-uk Kim     async_pool *pool;
139e71b7053SJung-uk Kim 
140e71b7053SJung-uk Kim     pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey);
141*b077aed3SPierre Pronchery     if (pool == NULL) {
142*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ERR_R_INTERNAL_ERROR);
143*b077aed3SPierre Pronchery         return;
144*b077aed3SPierre Pronchery     }
145e71b7053SJung-uk Kim     OPENSSL_free(job->funcargs);
146e71b7053SJung-uk Kim     job->funcargs = NULL;
147e71b7053SJung-uk Kim     sk_ASYNC_JOB_push(pool->jobs, job);
148e71b7053SJung-uk Kim }
149e71b7053SJung-uk Kim 
async_start_func(void)150e71b7053SJung-uk Kim void async_start_func(void)
151e71b7053SJung-uk Kim {
152e71b7053SJung-uk Kim     ASYNC_JOB *job;
153e71b7053SJung-uk Kim     async_ctx *ctx = async_get_ctx();
154e71b7053SJung-uk Kim 
155*b077aed3SPierre Pronchery     if (ctx == NULL) {
156*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ERR_R_INTERNAL_ERROR);
157*b077aed3SPierre Pronchery         return;
158*b077aed3SPierre Pronchery     }
159e71b7053SJung-uk Kim     while (1) {
160e71b7053SJung-uk Kim         /* Run the job */
161e71b7053SJung-uk Kim         job = ctx->currjob;
162e71b7053SJung-uk Kim         job->ret = job->func(job->funcargs);
163e71b7053SJung-uk Kim 
164e71b7053SJung-uk Kim         /* Stop the job */
165e71b7053SJung-uk Kim         job->status = ASYNC_JOB_STOPPING;
166e71b7053SJung-uk Kim         if (!async_fibre_swapcontext(&job->fibrectx,
167e71b7053SJung-uk Kim                                      &ctx->dispatcher, 1)) {
168e71b7053SJung-uk Kim             /*
169e71b7053SJung-uk Kim              * Should not happen. Getting here will close the thread...can't do
170e71b7053SJung-uk Kim              * much about it
171e71b7053SJung-uk Kim              */
172*b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
173e71b7053SJung-uk Kim         }
174e71b7053SJung-uk Kim     }
175e71b7053SJung-uk Kim }
176e71b7053SJung-uk Kim 
ASYNC_start_job(ASYNC_JOB ** job,ASYNC_WAIT_CTX * wctx,int * ret,int (* func)(void *),void * args,size_t size)177e71b7053SJung-uk Kim int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,
178e71b7053SJung-uk Kim                     int (*func)(void *), void *args, size_t size)
179e71b7053SJung-uk Kim {
180e71b7053SJung-uk Kim     async_ctx *ctx;
181*b077aed3SPierre Pronchery     OSSL_LIB_CTX *libctx;
182e71b7053SJung-uk Kim 
183e71b7053SJung-uk Kim     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
184e71b7053SJung-uk Kim         return ASYNC_ERR;
185e71b7053SJung-uk Kim 
186e71b7053SJung-uk Kim     ctx = async_get_ctx();
187e71b7053SJung-uk Kim     if (ctx == NULL)
188e71b7053SJung-uk Kim         ctx = async_ctx_new();
189e71b7053SJung-uk Kim     if (ctx == NULL)
190e71b7053SJung-uk Kim         return ASYNC_ERR;
191e71b7053SJung-uk Kim 
192*b077aed3SPierre Pronchery     if (*job != NULL)
193e71b7053SJung-uk Kim         ctx->currjob = *job;
194e71b7053SJung-uk Kim 
195e71b7053SJung-uk Kim     for (;;) {
196e71b7053SJung-uk Kim         if (ctx->currjob != NULL) {
197e71b7053SJung-uk Kim             if (ctx->currjob->status == ASYNC_JOB_STOPPING) {
198e71b7053SJung-uk Kim                 *ret = ctx->currjob->ret;
199e71b7053SJung-uk Kim                 ctx->currjob->waitctx = NULL;
200e71b7053SJung-uk Kim                 async_release_job(ctx->currjob);
201e71b7053SJung-uk Kim                 ctx->currjob = NULL;
202e71b7053SJung-uk Kim                 *job = NULL;
203e71b7053SJung-uk Kim                 return ASYNC_FINISH;
204e71b7053SJung-uk Kim             }
205e71b7053SJung-uk Kim 
206e71b7053SJung-uk Kim             if (ctx->currjob->status == ASYNC_JOB_PAUSING) {
207e71b7053SJung-uk Kim                 *job = ctx->currjob;
208e71b7053SJung-uk Kim                 ctx->currjob->status = ASYNC_JOB_PAUSED;
209e71b7053SJung-uk Kim                 ctx->currjob = NULL;
210e71b7053SJung-uk Kim                 return ASYNC_PAUSE;
211e71b7053SJung-uk Kim             }
212e71b7053SJung-uk Kim 
213e71b7053SJung-uk Kim             if (ctx->currjob->status == ASYNC_JOB_PAUSED) {
214*b077aed3SPierre Pronchery                 if (*job == NULL)
215*b077aed3SPierre Pronchery                     return ASYNC_ERR;
216e71b7053SJung-uk Kim                 ctx->currjob = *job;
217*b077aed3SPierre Pronchery 
218*b077aed3SPierre Pronchery                 /*
219*b077aed3SPierre Pronchery                  * Restore the default libctx to what it was the last time the
220*b077aed3SPierre Pronchery                  * fibre ran
221*b077aed3SPierre Pronchery                  */
222*b077aed3SPierre Pronchery                 libctx = OSSL_LIB_CTX_set0_default(ctx->currjob->libctx);
223*b077aed3SPierre Pronchery                 if (libctx == NULL) {
224*b077aed3SPierre Pronchery                     /* Failed to set the default context */
225*b077aed3SPierre Pronchery                     ERR_raise(ERR_LIB_ASYNC, ERR_R_INTERNAL_ERROR);
226*b077aed3SPierre Pronchery                     goto err;
227*b077aed3SPierre Pronchery                 }
228e71b7053SJung-uk Kim                 /* Resume previous job */
229e71b7053SJung-uk Kim                 if (!async_fibre_swapcontext(&ctx->dispatcher,
230e71b7053SJung-uk Kim                         &ctx->currjob->fibrectx, 1)) {
231*b077aed3SPierre Pronchery                     ctx->currjob->libctx = OSSL_LIB_CTX_set0_default(libctx);
232*b077aed3SPierre Pronchery                     ERR_raise(ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
233e71b7053SJung-uk Kim                     goto err;
234e71b7053SJung-uk Kim                 }
235*b077aed3SPierre Pronchery                 /*
236*b077aed3SPierre Pronchery                  * In case the fibre changed the default libctx we set it back
237*b077aed3SPierre Pronchery                  * again to what it was originally, and remember what it had
238*b077aed3SPierre Pronchery                  * been changed to.
239*b077aed3SPierre Pronchery                  */
240*b077aed3SPierre Pronchery                 ctx->currjob->libctx = OSSL_LIB_CTX_set0_default(libctx);
241e71b7053SJung-uk Kim                 continue;
242e71b7053SJung-uk Kim             }
243e71b7053SJung-uk Kim 
244e71b7053SJung-uk Kim             /* Should not happen */
245*b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_ASYNC, ERR_R_INTERNAL_ERROR);
246e71b7053SJung-uk Kim             async_release_job(ctx->currjob);
247e71b7053SJung-uk Kim             ctx->currjob = NULL;
248e71b7053SJung-uk Kim             *job = NULL;
249e71b7053SJung-uk Kim             return ASYNC_ERR;
250e71b7053SJung-uk Kim         }
251e71b7053SJung-uk Kim 
252e71b7053SJung-uk Kim         /* Start a new job */
253e71b7053SJung-uk Kim         if ((ctx->currjob = async_get_pool_job()) == NULL)
254e71b7053SJung-uk Kim             return ASYNC_NO_JOBS;
255e71b7053SJung-uk Kim 
256e71b7053SJung-uk Kim         if (args != NULL) {
257e71b7053SJung-uk Kim             ctx->currjob->funcargs = OPENSSL_malloc(size);
258e71b7053SJung-uk Kim             if (ctx->currjob->funcargs == NULL) {
259*b077aed3SPierre Pronchery                 ERR_raise(ERR_LIB_ASYNC, ERR_R_MALLOC_FAILURE);
260e71b7053SJung-uk Kim                 async_release_job(ctx->currjob);
261e71b7053SJung-uk Kim                 ctx->currjob = NULL;
262e71b7053SJung-uk Kim                 return ASYNC_ERR;
263e71b7053SJung-uk Kim             }
264e71b7053SJung-uk Kim             memcpy(ctx->currjob->funcargs, args, size);
265e71b7053SJung-uk Kim         } else {
266e71b7053SJung-uk Kim             ctx->currjob->funcargs = NULL;
267e71b7053SJung-uk Kim         }
268e71b7053SJung-uk Kim 
269e71b7053SJung-uk Kim         ctx->currjob->func = func;
270e71b7053SJung-uk Kim         ctx->currjob->waitctx = wctx;
271*b077aed3SPierre Pronchery         libctx = ossl_lib_ctx_get_concrete(NULL);
272e71b7053SJung-uk Kim         if (!async_fibre_swapcontext(&ctx->dispatcher,
273e71b7053SJung-uk Kim                 &ctx->currjob->fibrectx, 1)) {
274*b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
275e71b7053SJung-uk Kim             goto err;
276e71b7053SJung-uk Kim         }
277*b077aed3SPierre Pronchery         /*
278*b077aed3SPierre Pronchery          * In case the fibre changed the default libctx we set it back again
279*b077aed3SPierre Pronchery          * to what it was, and remember what it had been changed to.
280*b077aed3SPierre Pronchery          */
281*b077aed3SPierre Pronchery         ctx->currjob->libctx = OSSL_LIB_CTX_set0_default(libctx);
282e71b7053SJung-uk Kim     }
283e71b7053SJung-uk Kim 
284e71b7053SJung-uk Kim err:
285e71b7053SJung-uk Kim     async_release_job(ctx->currjob);
286e71b7053SJung-uk Kim     ctx->currjob = NULL;
287e71b7053SJung-uk Kim     *job = NULL;
288e71b7053SJung-uk Kim     return ASYNC_ERR;
289e71b7053SJung-uk Kim }
290e71b7053SJung-uk Kim 
ASYNC_pause_job(void)291e71b7053SJung-uk Kim int ASYNC_pause_job(void)
292e71b7053SJung-uk Kim {
293e71b7053SJung-uk Kim     ASYNC_JOB *job;
294e71b7053SJung-uk Kim     async_ctx *ctx = async_get_ctx();
295e71b7053SJung-uk Kim 
296e71b7053SJung-uk Kim     if (ctx == NULL
297e71b7053SJung-uk Kim             || ctx->currjob == NULL
298e71b7053SJung-uk Kim             || ctx->blocked) {
299e71b7053SJung-uk Kim         /*
300e71b7053SJung-uk Kim          * Could be we've deliberately not been started within a job so this is
301e71b7053SJung-uk Kim          * counted as success.
302e71b7053SJung-uk Kim          */
303e71b7053SJung-uk Kim         return 1;
304e71b7053SJung-uk Kim     }
305e71b7053SJung-uk Kim 
306e71b7053SJung-uk Kim     job = ctx->currjob;
307e71b7053SJung-uk Kim     job->status = ASYNC_JOB_PAUSING;
308e71b7053SJung-uk Kim 
309e71b7053SJung-uk Kim     if (!async_fibre_swapcontext(&job->fibrectx,
310e71b7053SJung-uk Kim                                  &ctx->dispatcher, 1)) {
311*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
312e71b7053SJung-uk Kim         return 0;
313e71b7053SJung-uk Kim     }
314e71b7053SJung-uk Kim     /* Reset counts of added and deleted fds */
315e71b7053SJung-uk Kim     async_wait_ctx_reset_counts(job->waitctx);
316e71b7053SJung-uk Kim 
317e71b7053SJung-uk Kim     return 1;
318e71b7053SJung-uk Kim }
319e71b7053SJung-uk Kim 
async_empty_pool(async_pool * pool)320e71b7053SJung-uk Kim static void async_empty_pool(async_pool *pool)
321e71b7053SJung-uk Kim {
322e71b7053SJung-uk Kim     ASYNC_JOB *job;
323e71b7053SJung-uk Kim 
324*b077aed3SPierre Pronchery     if (pool == NULL || pool->jobs == NULL)
325e71b7053SJung-uk Kim         return;
326e71b7053SJung-uk Kim 
327e71b7053SJung-uk Kim     do {
328e71b7053SJung-uk Kim         job = sk_ASYNC_JOB_pop(pool->jobs);
329e71b7053SJung-uk Kim         async_job_free(job);
330e71b7053SJung-uk Kim     } while (job);
331e71b7053SJung-uk Kim }
332e71b7053SJung-uk Kim 
async_init(void)333e71b7053SJung-uk Kim int async_init(void)
334e71b7053SJung-uk Kim {
335e71b7053SJung-uk Kim     if (!CRYPTO_THREAD_init_local(&ctxkey, NULL))
336e71b7053SJung-uk Kim         return 0;
337e71b7053SJung-uk Kim 
338e71b7053SJung-uk Kim     if (!CRYPTO_THREAD_init_local(&poolkey, NULL)) {
339e71b7053SJung-uk Kim         CRYPTO_THREAD_cleanup_local(&ctxkey);
340e71b7053SJung-uk Kim         return 0;
341e71b7053SJung-uk Kim     }
342e71b7053SJung-uk Kim 
343e71b7053SJung-uk Kim     return 1;
344e71b7053SJung-uk Kim }
345e71b7053SJung-uk Kim 
async_deinit(void)346e71b7053SJung-uk Kim void async_deinit(void)
347e71b7053SJung-uk Kim {
348e71b7053SJung-uk Kim     CRYPTO_THREAD_cleanup_local(&ctxkey);
349e71b7053SJung-uk Kim     CRYPTO_THREAD_cleanup_local(&poolkey);
350e71b7053SJung-uk Kim }
351e71b7053SJung-uk Kim 
ASYNC_init_thread(size_t max_size,size_t init_size)352e71b7053SJung-uk Kim int ASYNC_init_thread(size_t max_size, size_t init_size)
353e71b7053SJung-uk Kim {
354e71b7053SJung-uk Kim     async_pool *pool;
355e71b7053SJung-uk Kim     size_t curr_size = 0;
356e71b7053SJung-uk Kim 
357e71b7053SJung-uk Kim     if (init_size > max_size) {
358*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ASYNC_R_INVALID_POOL_SIZE);
359e71b7053SJung-uk Kim         return 0;
360e71b7053SJung-uk Kim     }
361e71b7053SJung-uk Kim 
362e71b7053SJung-uk Kim     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
363e71b7053SJung-uk Kim         return 0;
364e71b7053SJung-uk Kim 
365*b077aed3SPierre Pronchery     if (!ossl_init_thread_start(NULL, NULL, async_delete_thread_state))
366e71b7053SJung-uk Kim         return 0;
367e71b7053SJung-uk Kim 
368e71b7053SJung-uk Kim     pool = OPENSSL_zalloc(sizeof(*pool));
369e71b7053SJung-uk Kim     if (pool == NULL) {
370*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ERR_R_MALLOC_FAILURE);
371e71b7053SJung-uk Kim         return 0;
372e71b7053SJung-uk Kim     }
373e71b7053SJung-uk Kim 
374e71b7053SJung-uk Kim     pool->jobs = sk_ASYNC_JOB_new_reserve(NULL, init_size);
375e71b7053SJung-uk Kim     if (pool->jobs == NULL) {
376*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ERR_R_MALLOC_FAILURE);
377e71b7053SJung-uk Kim         OPENSSL_free(pool);
378e71b7053SJung-uk Kim         return 0;
379e71b7053SJung-uk Kim     }
380e71b7053SJung-uk Kim 
381e71b7053SJung-uk Kim     pool->max_size = max_size;
382e71b7053SJung-uk Kim 
383e71b7053SJung-uk Kim     /* Pre-create jobs as required */
384e71b7053SJung-uk Kim     while (init_size--) {
385e71b7053SJung-uk Kim         ASYNC_JOB *job;
386e71b7053SJung-uk Kim         job = async_job_new();
387e71b7053SJung-uk Kim         if (job == NULL || !async_fibre_makecontext(&job->fibrectx)) {
388e71b7053SJung-uk Kim             /*
389e71b7053SJung-uk Kim              * Not actually fatal because we already created the pool, just
390e71b7053SJung-uk Kim              * skip creation of any more jobs
391e71b7053SJung-uk Kim              */
392e71b7053SJung-uk Kim             async_job_free(job);
393e71b7053SJung-uk Kim             break;
394e71b7053SJung-uk Kim         }
395e71b7053SJung-uk Kim         job->funcargs = NULL;
396e71b7053SJung-uk Kim         sk_ASYNC_JOB_push(pool->jobs, job); /* Cannot fail due to reserve */
397e71b7053SJung-uk Kim         curr_size++;
398e71b7053SJung-uk Kim     }
399e71b7053SJung-uk Kim     pool->curr_size = curr_size;
400e71b7053SJung-uk Kim     if (!CRYPTO_THREAD_set_local(&poolkey, pool)) {
401*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SET_POOL);
402e71b7053SJung-uk Kim         goto err;
403e71b7053SJung-uk Kim     }
404e71b7053SJung-uk Kim 
405e71b7053SJung-uk Kim     return 1;
406e71b7053SJung-uk Kim err:
407e71b7053SJung-uk Kim     async_empty_pool(pool);
408e71b7053SJung-uk Kim     sk_ASYNC_JOB_free(pool->jobs);
409e71b7053SJung-uk Kim     OPENSSL_free(pool);
410e71b7053SJung-uk Kim     return 0;
411e71b7053SJung-uk Kim }
412e71b7053SJung-uk Kim 
async_delete_thread_state(void * arg)413*b077aed3SPierre Pronchery static void async_delete_thread_state(void *arg)
414e71b7053SJung-uk Kim {
415e71b7053SJung-uk Kim     async_pool *pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey);
416e71b7053SJung-uk Kim 
417e71b7053SJung-uk Kim     if (pool != NULL) {
418e71b7053SJung-uk Kim         async_empty_pool(pool);
419e71b7053SJung-uk Kim         sk_ASYNC_JOB_free(pool->jobs);
420e71b7053SJung-uk Kim         OPENSSL_free(pool);
421e71b7053SJung-uk Kim         CRYPTO_THREAD_set_local(&poolkey, NULL);
422e71b7053SJung-uk Kim     }
423e71b7053SJung-uk Kim     async_local_cleanup();
424e71b7053SJung-uk Kim     async_ctx_free();
425e71b7053SJung-uk Kim }
426e71b7053SJung-uk Kim 
ASYNC_cleanup_thread(void)427e71b7053SJung-uk Kim void ASYNC_cleanup_thread(void)
428e71b7053SJung-uk Kim {
429e71b7053SJung-uk Kim     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
430e71b7053SJung-uk Kim         return;
431e71b7053SJung-uk Kim 
432*b077aed3SPierre Pronchery     async_delete_thread_state(NULL);
433e71b7053SJung-uk Kim }
434e71b7053SJung-uk Kim 
ASYNC_get_current_job(void)435e71b7053SJung-uk Kim ASYNC_JOB *ASYNC_get_current_job(void)
436e71b7053SJung-uk Kim {
437e71b7053SJung-uk Kim     async_ctx *ctx;
438e71b7053SJung-uk Kim 
439e71b7053SJung-uk Kim     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
440e71b7053SJung-uk Kim         return NULL;
441e71b7053SJung-uk Kim 
442e71b7053SJung-uk Kim     ctx = async_get_ctx();
443e71b7053SJung-uk Kim     if (ctx == NULL)
444e71b7053SJung-uk Kim         return NULL;
445e71b7053SJung-uk Kim 
446e71b7053SJung-uk Kim     return ctx->currjob;
447e71b7053SJung-uk Kim }
448e71b7053SJung-uk Kim 
ASYNC_get_wait_ctx(ASYNC_JOB * job)449e71b7053SJung-uk Kim ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job)
450e71b7053SJung-uk Kim {
451e71b7053SJung-uk Kim     return job->waitctx;
452e71b7053SJung-uk Kim }
453e71b7053SJung-uk Kim 
ASYNC_block_pause(void)454e71b7053SJung-uk Kim void ASYNC_block_pause(void)
455e71b7053SJung-uk Kim {
456e71b7053SJung-uk Kim     async_ctx *ctx;
457e71b7053SJung-uk Kim 
458e71b7053SJung-uk Kim     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
459e71b7053SJung-uk Kim         return;
460e71b7053SJung-uk Kim 
461e71b7053SJung-uk Kim     ctx = async_get_ctx();
462e71b7053SJung-uk Kim     if (ctx == NULL || ctx->currjob == NULL) {
463e71b7053SJung-uk Kim         /*
464e71b7053SJung-uk Kim          * We're not in a job anyway so ignore this
465e71b7053SJung-uk Kim          */
466e71b7053SJung-uk Kim         return;
467e71b7053SJung-uk Kim     }
468e71b7053SJung-uk Kim     ctx->blocked++;
469e71b7053SJung-uk Kim }
470e71b7053SJung-uk Kim 
ASYNC_unblock_pause(void)471e71b7053SJung-uk Kim void ASYNC_unblock_pause(void)
472e71b7053SJung-uk Kim {
473e71b7053SJung-uk Kim     async_ctx *ctx;
474e71b7053SJung-uk Kim 
475e71b7053SJung-uk Kim     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
476e71b7053SJung-uk Kim         return;
477e71b7053SJung-uk Kim 
478e71b7053SJung-uk Kim     ctx = async_get_ctx();
479e71b7053SJung-uk Kim     if (ctx == NULL || ctx->currjob == NULL) {
480e71b7053SJung-uk Kim         /*
481e71b7053SJung-uk Kim          * We're not in a job anyway so ignore this
482e71b7053SJung-uk Kim          */
483e71b7053SJung-uk Kim         return;
484e71b7053SJung-uk Kim     }
485e71b7053SJung-uk Kim     if (ctx->blocked > 0)
486e71b7053SJung-uk Kim         ctx->blocked--;
487e71b7053SJung-uk Kim }
488