Coverage Report

Created: 2024-07-24 06:31

/src/openssl/crypto/thread/arch.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019-2023 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
#include <openssl/configuration.h>
11
#include <internal/thread_arch.h>
12
13
CRYPTO_THREAD *ossl_crypto_thread_native_start(CRYPTO_THREAD_ROUTINE routine,
14
                                               void *data, int joinable)
15
0
{
16
0
    CRYPTO_THREAD *handle;
17
18
0
    if (routine == NULL)
19
0
        return NULL;
20
21
0
    handle = OPENSSL_zalloc(sizeof(*handle));
22
0
    if (handle == NULL)
23
0
        return NULL;
24
25
0
    if ((handle->lock = ossl_crypto_mutex_new()) == NULL)
26
0
        goto fail;
27
0
    if ((handle->statelock = ossl_crypto_mutex_new()) == NULL)
28
0
        goto fail;
29
0
    if ((handle->condvar = ossl_crypto_condvar_new()) == NULL)
30
0
        goto fail;
31
32
0
    handle->data = data;
33
0
    handle->routine = routine;
34
0
    handle->joinable = joinable;
35
36
0
    if (ossl_crypto_thread_native_spawn(handle) == 1)
37
0
        return handle;
38
39
0
fail:
40
0
    ossl_crypto_condvar_free(&handle->condvar);
41
0
    ossl_crypto_mutex_free(&handle->statelock);
42
0
    ossl_crypto_mutex_free(&handle->lock);
43
0
    OPENSSL_free(handle);
44
0
    return NULL;
45
0
}
46
47
int ossl_crypto_thread_native_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
48
0
{
49
0
    uint64_t req_state_mask;
50
51
0
    if (thread == NULL)
52
0
        return 0;
53
54
0
    ossl_crypto_mutex_lock(thread->statelock);
55
0
    req_state_mask = CRYPTO_THREAD_FINISHED | CRYPTO_THREAD_JOINED;
56
0
    while (!CRYPTO_THREAD_GET_STATE(thread, req_state_mask))
57
0
        ossl_crypto_condvar_wait(thread->condvar, thread->statelock);
58
59
0
    if (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
60
0
        goto pass;
61
62
    /* Await concurrent join completion, if any. */
63
0
    while (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT)) {
64
0
        if (!CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
65
0
            ossl_crypto_condvar_wait(thread->condvar, thread->statelock);
66
0
        if (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
67
0
            goto pass;
68
0
    }
69
0
    CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT);
70
0
    ossl_crypto_mutex_unlock(thread->statelock);
71
72
0
    if (ossl_crypto_thread_native_perform_join(thread, retval) == 0)
73
0
        goto fail;
74
75
0
    ossl_crypto_mutex_lock(thread->statelock);
76
0
pass:
77
0
    CRYPTO_THREAD_UNSET_ERROR(thread, CRYPTO_THREAD_JOINED);
78
0
    CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_JOINED);
79
80
    /*
81
     * Signal join completion. It is important to signal even if we haven't
82
     * performed an actual join. Multiple threads could be awaiting the
83
     * CRYPTO_THREAD_JOIN_AWAIT -> CRYPTO_THREAD_JOINED transition, but signal
84
     * on actual join would wake only one. Signalling here will always wake one.
85
     */
86
0
    ossl_crypto_condvar_signal(thread->condvar);
87
0
    ossl_crypto_mutex_unlock(thread->statelock);
88
89
0
    if (retval != NULL)
90
0
        *retval = thread->retval;
91
0
    return 1;
92
93
0
fail:
94
0
    ossl_crypto_mutex_lock(thread->statelock);
95
0
    CRYPTO_THREAD_SET_ERROR(thread, CRYPTO_THREAD_JOINED);
96
97
    /* Have another thread that's awaiting join retry to avoid that
98
     * thread deadlock. */
99
0
    CRYPTO_THREAD_UNSET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT);
100
0
    ossl_crypto_condvar_signal(thread->condvar);
101
102
0
    ossl_crypto_mutex_unlock(thread->statelock);
103
0
    return 0;
104
0
}
105
106
int ossl_crypto_thread_native_clean(CRYPTO_THREAD *handle)
107
0
{
108
0
    uint64_t req_state_mask;
109
110
0
    if (handle == NULL)
111
0
        return 0;
112
113
0
    req_state_mask = 0;
114
0
    req_state_mask |= CRYPTO_THREAD_FINISHED;
115
0
    req_state_mask |= CRYPTO_THREAD_JOINED;
116
117
0
    ossl_crypto_mutex_lock(handle->statelock);
118
0
    if (CRYPTO_THREAD_GET_STATE(handle, req_state_mask) == 0) {
119
0
        ossl_crypto_mutex_unlock(handle->statelock);
120
0
        return 0;
121
0
    }
122
0
    ossl_crypto_mutex_unlock(handle->statelock);
123
124
0
    ossl_crypto_mutex_free(&handle->lock);
125
0
    ossl_crypto_mutex_free(&handle->statelock);
126
0
    ossl_crypto_condvar_free(&handle->condvar);
127
128
0
    OPENSSL_free(handle->handle);
129
0
    OPENSSL_free(handle);
130
131
0
    return 1;
132
0
}