summaryrefslogtreecommitdiff
path: root/crypto/async/arch/async_posix.c
blob: f2b507c7d0a6450e5e1f96ce6558630df3393624 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

/* This must be the first #include file */
#include "../async_local.h"

#ifdef ASYNC_POSIX

# include <stddef.h>
# include <unistd.h>
# include <openssl/err.h>
# include <openssl/crypto.h>

#define STACKSIZE       32768

static CRYPTO_RWLOCK *async_mem_lock;

static void *async_stack_alloc(size_t *num);
static void async_stack_free(void *addr);

int async_local_init(void)
{
    async_mem_lock = CRYPTO_THREAD_lock_new();
    return async_mem_lock != NULL;
}

void async_local_deinit(void)
{
    CRYPTO_THREAD_lock_free(async_mem_lock);
}

static int allow_customize = 1;
static ASYNC_stack_alloc_fn stack_alloc_impl = async_stack_alloc;
static ASYNC_stack_free_fn stack_free_impl = async_stack_free;

int ASYNC_is_capable(void)
{
    ucontext_t ctx;

    /*
     * Some platforms provide getcontext() but it does not work (notably
     * MacOSX PPC64). Check for a working getcontext();
     */
    return getcontext(&ctx) == 0;
}

int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn,
                            ASYNC_stack_free_fn free_fn)
{
    OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL);

    if (!CRYPTO_THREAD_write_lock(async_mem_lock))
        return 0;
    if (!allow_customize) {
        CRYPTO_THREAD_unlock(async_mem_lock);
        return 0;
    }
    CRYPTO_THREAD_unlock(async_mem_lock);

    if (alloc_fn != NULL)
        stack_alloc_impl = alloc_fn;
    if (free_fn != NULL)
        stack_free_impl = free_fn;
    return 1;
}

void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn,
                             ASYNC_stack_free_fn *free_fn)
{
    if (alloc_fn != NULL)
        *alloc_fn = stack_alloc_impl;
    if (free_fn != NULL)
        *free_fn = stack_free_impl;
}

static void *async_stack_alloc(size_t *num)
{
    return OPENSSL_malloc(*num);
}

static void async_stack_free(void *addr)
{
    OPENSSL_free(addr);
}

void async_local_cleanup(void)
{
}

int async_fibre_makecontext(async_fibre *fibre)
{
#ifndef USE_SWAPCONTEXT
    fibre->env_init = 0;
#endif
    if (getcontext(&fibre->fibre) == 0) {
        size_t num = STACKSIZE;

        /*
         *  Disallow customisation after the first
         *  stack is allocated.
         */
        if (allow_customize) {
            if (!CRYPTO_THREAD_write_lock(async_mem_lock))
                return 0;
            allow_customize = 0;
            CRYPTO_THREAD_unlock(async_mem_lock);
        }

        fibre->fibre.uc_stack.ss_sp = stack_alloc_impl(&num);
        if (fibre->fibre.uc_stack.ss_sp != NULL) {
            fibre->fibre.uc_stack.ss_size = num;
            fibre->fibre.uc_link = NULL;
            makecontext(&fibre->fibre, async_start_func, 0);
            return 1;
        }
    } else {
        fibre->fibre.uc_stack.ss_sp = NULL;
    }
    return 0;
}

void async_fibre_free(async_fibre *fibre)
{
    stack_free_impl(fibre->fibre.uc_stack.ss_sp);
    fibre->fibre.uc_stack.ss_sp = NULL;
}

#endif