1 /* 2 * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* This must be the first #include file */ 11 #include "../async_local.h" 12 13 #ifdef ASYNC_POSIX 14 15 # include <stddef.h> 16 # include <unistd.h> 17 # include <openssl/err.h> 18 # include <openssl/crypto.h> 19 20 #define STACKSIZE 32768 21 22 static CRYPTO_RWLOCK *async_mem_lock; 23 24 static void *async_stack_alloc(size_t *num); 25 static void async_stack_free(void *addr); 26 async_local_init(void)27int async_local_init(void) 28 { 29 async_mem_lock = CRYPTO_THREAD_lock_new(); 30 return async_mem_lock != NULL; 31 } 32 async_local_deinit(void)33void async_local_deinit(void) 34 { 35 CRYPTO_THREAD_lock_free(async_mem_lock); 36 } 37 38 static int allow_customize = 1; 39 static ASYNC_stack_alloc_fn stack_alloc_impl = async_stack_alloc; 40 static ASYNC_stack_free_fn stack_free_impl = async_stack_free; 41 ASYNC_is_capable(void)42int ASYNC_is_capable(void) 43 { 44 ucontext_t ctx; 45 46 /* 47 * Some platforms provide getcontext() but it does not work (notably 48 * MacOSX PPC64). Check for a working getcontext(); 49 */ 50 return getcontext(&ctx) == 0; 51 } 52 ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn,ASYNC_stack_free_fn free_fn)53int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn, 54 ASYNC_stack_free_fn free_fn) 55 { 56 OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL); 57 58 if (!CRYPTO_THREAD_write_lock(async_mem_lock)) 59 return 0; 60 if (!allow_customize) { 61 CRYPTO_THREAD_unlock(async_mem_lock); 62 return 0; 63 } 64 CRYPTO_THREAD_unlock(async_mem_lock); 65 66 if (alloc_fn != NULL) 67 stack_alloc_impl = alloc_fn; 68 if (free_fn != NULL) 69 stack_free_impl = free_fn; 70 return 1; 71 } 72 ASYNC_get_mem_functions(ASYNC_stack_alloc_fn * alloc_fn,ASYNC_stack_free_fn * free_fn)73void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn, 74 ASYNC_stack_free_fn *free_fn) 75 { 76 if (alloc_fn != NULL) 77 *alloc_fn = stack_alloc_impl; 78 if (free_fn != NULL) 79 *free_fn = stack_free_impl; 80 } 81 async_stack_alloc(size_t * num)82static void *async_stack_alloc(size_t *num) 83 { 84 return OPENSSL_malloc(*num); 85 } 86 async_stack_free(void * addr)87static void async_stack_free(void *addr) 88 { 89 OPENSSL_free(addr); 90 } 91 async_local_cleanup(void)92void async_local_cleanup(void) 93 { 94 } 95 async_fibre_makecontext(async_fibre * fibre)96int async_fibre_makecontext(async_fibre *fibre) 97 { 98 #ifndef USE_SWAPCONTEXT 99 fibre->env_init = 0; 100 #endif 101 if (getcontext(&fibre->fibre) == 0) { 102 size_t num = STACKSIZE; 103 104 /* 105 * Disallow customisation after the first 106 * stack is allocated. 107 */ 108 if (allow_customize) { 109 if (!CRYPTO_THREAD_write_lock(async_mem_lock)) 110 return 0; 111 allow_customize = 0; 112 CRYPTO_THREAD_unlock(async_mem_lock); 113 } 114 115 fibre->fibre.uc_stack.ss_sp = stack_alloc_impl(&num); 116 if (fibre->fibre.uc_stack.ss_sp != NULL) { 117 fibre->fibre.uc_stack.ss_size = num; 118 fibre->fibre.uc_link = NULL; 119 makecontext(&fibre->fibre, async_start_func, 0); 120 return 1; 121 } 122 } else { 123 fibre->fibre.uc_stack.ss_sp = NULL; 124 } 125 return 0; 126 } 127 async_fibre_free(async_fibre * fibre)128void async_fibre_free(async_fibre *fibre) 129 { 130 stack_free_impl(fibre->fibre.uc_stack.ss_sp); 131 fibre->fibre.uc_stack.ss_sp = NULL; 132 } 133 134 #endif 135