]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/async/async.c
Refactor the async wait fd logic
[thirdparty/openssl.git] / crypto / async / async.c
CommitLineData
a3667c31
MC
1/*
2 * Written by Matt Caswell (matt@openssl.org) for the OpenSSL project.
3 */
4/* ====================================================================
5 * Copyright (c) 2015 The OpenSSL Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. All advertising materials mentioning features or use of this
20 * software must display the following acknowledgment:
21 * "This product includes software developed by the OpenSSL Project
22 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23 *
24 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25 * endorse or promote products derived from this software without
26 * prior written permission. For written permission, please contact
27 * licensing@OpenSSL.org.
28 *
29 * 5. Products derived from this software may not be called "OpenSSL"
30 * nor may "OpenSSL" appear in their names without prior written
31 * permission of the OpenSSL Project.
32 *
33 * 6. Redistributions of any form whatsoever must retain the following
34 * acknowledgment:
35 * "This product includes software developed by the OpenSSL Project
36 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49 * OF THE POSSIBILITY OF SUCH DAMAGE.
50 * ====================================================================
51 */
52
4abc7681
MC
53/*
54 * Without this we start getting longjmp crashes because it thinks we're jumping
55 * up the stack when in fact we are jumping to an entirely different stack. The
56 * cost of this is not having certain buffer overrun/underrun checks etc for
57 * this source file :-(
58 */
59#undef _FORTIFY_SOURCE
60
6e8ac508
VD
61/* This must be the first #include file */
62#include "async_locl.h"
63
079a1a90 64#include <openssl/err.h>
7b9f8f7f 65#include <internal/cryptlib_int.h>
a3667c31
MC
66#include <string.h>
67
68#define ASYNC_JOB_RUNNING 0
69#define ASYNC_JOB_PAUSING 1
70#define ASYNC_JOB_PAUSED 2
71#define ASYNC_JOB_STOPPING 3
72
27949c35
MC
73static void async_free_pool_internal(async_pool *pool);
74
636ca4ff 75static async_ctx *async_ctx_new(void)
a3667c31 76{
636ca4ff 77 async_ctx *nctx = NULL;
a3667c31 78
e38565f5
MC
79 nctx = OPENSSL_malloc(sizeof (async_ctx));
80 if (nctx == NULL) {
079a1a90 81 ASYNCerr(ASYNC_F_ASYNC_CTX_NEW, ERR_R_MALLOC_FAILURE);
a3667c31
MC
82 goto err;
83 }
84
636ca4ff 85 async_fibre_init_dispatcher(&nctx->dispatcher);
a3667c31 86 nctx->currjob = NULL;
e8dfb5bf 87 nctx->blocked = 0;
e38565f5 88 if (!async_set_ctx(nctx))
9ec1e031 89 goto err;
a3667c31
MC
90
91 return nctx;
92err:
e38565f5 93 OPENSSL_free(nctx);
a3667c31
MC
94
95 return NULL;
96}
97
7b9f8f7f
MC
98static async_ctx *async_get_ctx(void)
99{
0fc32b07
MC
100 if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
101 return NULL;
7b9f8f7f
MC
102 return async_arch_get_ctx();
103}
104
636ca4ff 105static int async_ctx_free(void)
a3667c31 106{
e38565f5 107 async_ctx *ctx;
a3667c31 108
e38565f5
MC
109 ctx = async_get_ctx();
110
111 if (!async_set_ctx(NULL))
9ec1e031 112 return 0;
a3667c31 113
e38565f5
MC
114 OPENSSL_free(ctx);
115
a3667c31
MC
116 return 1;
117}
118
636ca4ff 119static ASYNC_JOB *async_job_new(void)
a3667c31
MC
120{
121 ASYNC_JOB *job = NULL;
a3667c31 122
ff75a257 123 job = OPENSSL_zalloc(sizeof (ASYNC_JOB));
e38565f5 124 if (job == NULL) {
079a1a90 125 ASYNCerr(ASYNC_F_ASYNC_JOB_NEW, ERR_R_MALLOC_FAILURE);
50108304 126 return NULL;
a3667c31
MC
127 }
128
a3667c31 129 job->status = ASYNC_JOB_RUNNING;
a3667c31
MC
130
131 return job;
a3667c31
MC
132}
133
636ca4ff 134static void async_job_free(ASYNC_JOB *job)
a3667c31 135{
e38565f5
MC
136 if (job != NULL) {
137 OPENSSL_free(job->funcargs);
636ca4ff 138 async_fibre_free(&job->fibrectx);
a3667c31
MC
139 OPENSSL_free(job);
140 }
141}
142
252d6d3a 143static ASYNC_JOB *async_get_pool_job(void) {
a3667c31 144 ASYNC_JOB *job;
27949c35 145 async_pool *pool;
a3667c31 146
0ff2b9ac 147 pool = async_get_pool();
252d6d3a 148 if (pool == NULL) {
50108304 149 /*
252d6d3a 150 * Pool has not been initialised, so init with the defaults, i.e.
9f078e19 151 * no max size and no pre-created jobs
50108304 152 */
68487a9b 153 if (ASYNC_init_thread(0, 0) == 0)
252d6d3a 154 return NULL;
0ff2b9ac 155 pool = async_get_pool();
252d6d3a
MC
156 }
157
27949c35 158 job = sk_ASYNC_JOB_pop(pool->jobs);
252d6d3a
MC
159 if (job == NULL) {
160 /* Pool is empty */
27949c35 161 if ((pool->max_size != 0) && (pool->curr_size >= pool->max_size))
252d6d3a 162 return NULL;
0ff2b9ac 163
636ca4ff 164 job = async_job_new();
6e8ac508
VD
165 if (job != NULL) {
166 if (! async_fibre_makecontext(&job->fibrectx)) {
167 async_job_free(job);
168 return NULL;
169 }
27949c35 170 pool->curr_size++;
252d6d3a
MC
171 }
172 }
173 return job;
174}
175
176static void async_release_job(ASYNC_JOB *job) {
27949c35
MC
177 async_pool *pool;
178
179 pool = async_get_pool();
e38565f5 180 OPENSSL_free(job->funcargs);
252d6d3a 181 job->funcargs = NULL;
27949c35 182 sk_ASYNC_JOB_push(pool->jobs, job);
252d6d3a
MC
183}
184
636ca4ff 185void async_start_func(void)
252d6d3a
MC
186{
187 ASYNC_JOB *job;
7b9f8f7f 188 async_ctx *ctx = async_get_ctx();
252d6d3a
MC
189
190 while (1) {
191 /* Run the job */
7b9f8f7f 192 job = ctx->currjob;
252d6d3a
MC
193 job->ret = job->func(job->funcargs);
194
195 /* Stop the job */
196 job->status = ASYNC_JOB_STOPPING;
e38565f5 197 if (!async_fibre_swapcontext(&job->fibrectx,
7b9f8f7f 198 &ctx->dispatcher, 1)) {
252d6d3a 199 /*
079a1a90
MC
200 * Should not happen. Getting here will close the thread...can't do
201 * much about it
252d6d3a 202 */
079a1a90 203 ASYNCerr(ASYNC_F_ASYNC_START_FUNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
252d6d3a 204 }
50108304 205 }
a3667c31
MC
206}
207
ff75a257
MC
208int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,
209 int (*func)(void *), void *args, size_t size)
a3667c31 210{
7b9f8f7f
MC
211 async_ctx *ctx = async_get_ctx();
212 if (ctx == NULL)
213 ctx = async_ctx_new();
214 if (ctx == NULL) {
a3667c31
MC
215 return ASYNC_ERR;
216 }
217
e38565f5 218 if (*job) {
7b9f8f7f 219 ctx->currjob = *job;
a3667c31
MC
220 }
221
50108304 222 for (;;) {
7b9f8f7f
MC
223 if (ctx->currjob != NULL) {
224 if (ctx->currjob->status == ASYNC_JOB_STOPPING) {
225 *ret = ctx->currjob->ret;
ff75a257 226 ctx->currjob->waitctx = NULL;
7b9f8f7f
MC
227 async_release_job(ctx->currjob);
228 ctx->currjob = NULL;
82676094 229 *job = NULL;
50108304
MC
230 return ASYNC_FINISH;
231 }
232
7b9f8f7f
MC
233 if (ctx->currjob->status == ASYNC_JOB_PAUSING) {
234 *job = ctx->currjob;
235 ctx->currjob->status = ASYNC_JOB_PAUSED;
236 ctx->currjob = NULL;
50108304
MC
237 return ASYNC_PAUSE;
238 }
239
7b9f8f7f
MC
240 if (ctx->currjob->status == ASYNC_JOB_PAUSED) {
241 ctx->currjob = *job;
50108304 242 /* Resume previous job */
7b9f8f7f
MC
243 if (!async_fibre_swapcontext(&ctx->dispatcher,
244 &ctx->currjob->fibrectx, 1)) {
079a1a90
MC
245 ASYNCerr(ASYNC_F_ASYNC_START_JOB,
246 ASYNC_R_FAILED_TO_SWAP_CONTEXT);
50108304 247 goto err;
079a1a90 248 }
50108304
MC
249 continue;
250 }
251
252 /* Should not happen */
079a1a90 253 ASYNCerr(ASYNC_F_ASYNC_START_JOB, ERR_R_INTERNAL_ERROR);
7b9f8f7f
MC
254 async_release_job(ctx->currjob);
255 ctx->currjob = NULL;
82676094 256 *job = NULL;
50108304 257 return ASYNC_ERR;
a3667c31
MC
258 }
259
50108304 260 /* Start a new job */
7b9f8f7f 261 if ((ctx->currjob = async_get_pool_job()) == NULL) {
252d6d3a 262 return ASYNC_NO_JOBS;
a3667c31
MC
263 }
264
e38565f5 265 if (args != NULL) {
7b9f8f7f
MC
266 ctx->currjob->funcargs = OPENSSL_malloc(size);
267 if (ctx->currjob->funcargs == NULL) {
079a1a90 268 ASYNCerr(ASYNC_F_ASYNC_START_JOB, ERR_R_MALLOC_FAILURE);
7b9f8f7f
MC
269 async_release_job(ctx->currjob);
270 ctx->currjob = NULL;
50108304
MC
271 return ASYNC_ERR;
272 }
7b9f8f7f 273 memcpy(ctx->currjob->funcargs, args, size);
50108304 274 } else {
7b9f8f7f 275 ctx->currjob->funcargs = NULL;
a3667c31
MC
276 }
277
7b9f8f7f 278 ctx->currjob->func = func;
ff75a257 279 ctx->currjob->waitctx = wctx;
7b9f8f7f
MC
280 if (!async_fibre_swapcontext(&ctx->dispatcher,
281 &ctx->currjob->fibrectx, 1)) {
079a1a90 282 ASYNCerr(ASYNC_F_ASYNC_START_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
50108304 283 goto err;
079a1a90 284 }
a3667c31
MC
285 }
286
50108304 287err:
7b9f8f7f
MC
288 async_release_job(ctx->currjob);
289 ctx->currjob = NULL;
82676094 290 *job = NULL;
a3667c31
MC
291 return ASYNC_ERR;
292}
293
a3667c31
MC
294int ASYNC_pause_job(void)
295{
296 ASYNC_JOB *job;
7b9f8f7f 297 async_ctx *ctx = async_get_ctx();
a3667c31 298
7b9f8f7f
MC
299 if (ctx == NULL
300 || ctx->currjob == NULL
301 || ctx->blocked) {
079a1a90 302 /*
05a6347f
MC
303 * Could be we've deliberately not been started within a job so this is
304 * counted as success.
079a1a90 305 */
05a6347f 306 return 1;
079a1a90 307 }
a3667c31 308
7b9f8f7f 309 job = ctx->currjob;
a3667c31
MC
310 job->status = ASYNC_JOB_PAUSING;
311
e8dfb5bf 312 if (!async_fibre_swapcontext(&job->fibrectx,
7b9f8f7f 313 &ctx->dispatcher, 1)) {
079a1a90 314 ASYNCerr(ASYNC_F_ASYNC_PAUSE_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
a3667c31
MC
315 return 0;
316 }
ff75a257
MC
317 /* Reset counts of added and deleted fds */
318 async_wait_ctx_reset_counts(job->waitctx);
a3667c31
MC
319
320 return 1;
321}
322
27949c35 323static void async_empty_pool(async_pool *pool)
d63de0eb
MC
324{
325 ASYNC_JOB *job;
326
27949c35
MC
327 if (!pool || !pool->jobs)
328 return;
329
d63de0eb 330 do {
27949c35 331 job = sk_ASYNC_JOB_pop(pool->jobs);
636ca4ff 332 async_job_free(job);
d63de0eb
MC
333 } while (job);
334}
335
7b9f8f7f 336int async_init(void)
68487a9b 337{
22a34c2f 338 if (!async_global_init())
68487a9b
MC
339 return 0;
340
68487a9b
MC
341 return 1;
342}
343
344int ASYNC_init_thread(size_t max_size, size_t init_size)
252d6d3a 345{
27949c35 346 async_pool *pool;
0ff2b9ac
MC
347 size_t curr_size = 0;
348
68487a9b
MC
349 if (init_size > max_size) {
350 ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ASYNC_R_INVALID_POOL_SIZE);
27949c35
MC
351 return 0;
352 }
353
0fc32b07 354 if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL)) {
0fc32b07
MC
355 return 0;
356 }
7b9f8f7f 357 if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_ASYNC)) {
22a34c2f
MC
358 return 0;
359 }
7b9f8f7f 360
27949c35 361 pool = OPENSSL_zalloc(sizeof *pool);
252d6d3a 362 if (pool == NULL) {
68487a9b 363 ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ERR_R_MALLOC_FAILURE);
252d6d3a
MC
364 return 0;
365 }
27949c35
MC
366
367 pool->jobs = sk_ASYNC_JOB_new_null();
368 if (pool->jobs == NULL) {
68487a9b 369 ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ERR_R_MALLOC_FAILURE);
27949c35
MC
370 OPENSSL_free(pool);
371 return 0;
372 }
373
374 pool->max_size = max_size;
375
252d6d3a 376 /* Pre-create jobs as required */
6e8ac508 377 while (init_size--) {
252d6d3a 378 ASYNC_JOB *job;
636ca4ff 379 job = async_job_new();
6e8ac508 380 if (job == NULL || !async_fibre_makecontext(&job->fibrectx)) {
252d6d3a 381 /*
6e8ac508
VD
382 * Not actually fatal because we already created the pool, just
383 * skip creation of any more jobs
252d6d3a 384 */
6e8ac508
VD
385 async_job_free(job);
386 break;
252d6d3a 387 }
6e8ac508
VD
388 job->funcargs = NULL;
389 sk_ASYNC_JOB_push(pool->jobs, job);
390 curr_size++;
252d6d3a 391 }
27949c35 392 pool->curr_size = curr_size;
27949c35 393 if (!async_set_pool(pool)) {
68487a9b 394 ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ASYNC_R_FAILED_TO_SET_POOL);
27949c35 395 goto err;
d63de0eb 396 }
0ff2b9ac 397
252d6d3a 398 return 1;
27949c35
MC
399err:
400 async_free_pool_internal(pool);
401 return 0;
252d6d3a
MC
402}
403
27949c35 404static void async_free_pool_internal(async_pool *pool)
252d6d3a 405{
0ff2b9ac
MC
406 if (pool == NULL)
407 return;
d63de0eb
MC
408
409 async_empty_pool(pool);
27949c35
MC
410 sk_ASYNC_JOB_free(pool->jobs);
411 OPENSSL_free(pool);
68487a9b 412 (void)async_set_pool(NULL);
22a34c2f 413 async_local_cleanup();
636ca4ff 414 async_ctx_free();
252d6d3a 415}
f4da39d2 416
68487a9b 417void ASYNC_cleanup_thread(void)
27949c35
MC
418{
419 async_free_pool_internal(async_get_pool());
420}
421
f4da39d2
MC
422ASYNC_JOB *ASYNC_get_current_job(void)
423{
636ca4ff 424 async_ctx *ctx;
e38565f5
MC
425
426 ctx = async_get_ctx();
427 if(ctx == NULL)
f4da39d2
MC
428 return NULL;
429
430 return ctx->currjob;
431}
432
ff75a257 433ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job)
f4da39d2 434{
ff75a257 435 return job->waitctx;
f4da39d2 436}
e8dfb5bf
MC
437
438void ASYNC_block_pause(void)
439{
7b9f8f7f
MC
440 async_ctx *ctx = async_get_ctx();
441 if (ctx == NULL || ctx->currjob == NULL) {
e8dfb5bf
MC
442 /*
443 * We're not in a job anyway so ignore this
444 */
445 return;
446 }
7b9f8f7f 447 ctx->blocked++;
e8dfb5bf
MC
448}
449
450void ASYNC_unblock_pause(void)
451{
7b9f8f7f
MC
452 async_ctx *ctx = async_get_ctx();
453 if (ctx == NULL || ctx->currjob == NULL) {
e8dfb5bf
MC
454 /*
455 * We're not in a job anyway so ignore this
456 */
457 return;
458 }
7b9f8f7f
MC
459 if(ctx->blocked > 0)
460 ctx->blocked--;
e8dfb5bf 461}