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