Home | History | Annotate | Line # | Download | only in arch
      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 
     27 int async_local_init(void)
     28 {
     29     async_mem_lock = CRYPTO_THREAD_lock_new();
     30     return async_mem_lock != NULL;
     31 }
     32 
     33 void 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 
     42 int 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 
     53 int 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 
     73 void 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 
     82 static void *async_stack_alloc(size_t *num)
     83 {
     84     return OPENSSL_malloc(*num);
     85 }
     86 
     87 static void async_stack_free(void *addr)
     88 {
     89     OPENSSL_free(addr);
     90 }
     91 
     92 void async_local_cleanup(void)
     93 {
     94 }
     95 
     96 int 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 
    128 void 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