Coverage Report

Created: 2026-05-20 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/threads_pthread.c
Line
Count
Source
1
/*
2
 * Copyright 2016-2026 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
/* We need to use the OPENSSL_fork_*() deprecated APIs */
11
#define OPENSSL_SUPPRESS_DEPRECATED
12
13
#if !defined(__GNUC__) || !defined(__ATOMIC_ACQ_REL) || defined(BROKEN_CLANG_ATOMICS) || defined(OPENSSL_NO_STDIO)
14
/*
15
 * we only enable REPORT_RWLOCK_CONTENTION on clang/gcc when we have
16
 * atomics available.  We do this because we need to use an atomic to track
17
 * when we can close the log file.  We could use the CRYPTO_atomic_ api
18
 * but that requires lock creation which gets us into a bad recursive loop
19
 * when we try to initialize the file pointer
20
 */
21
#ifdef REPORT_RWLOCK_CONTENTION
22
#warning "RWLOCK CONTENTION REPORTING NOT SUPPORTED, Disabling"
23
#undef REPORT_RWLOCK_CONTENTION
24
#endif
25
#endif
26
27
#ifdef REPORT_RWLOCK_CONTENTION
28
#define _GNU_SOURCE
29
#include <execinfo.h>
30
#include <unistd.h>
31
#endif
32
33
#include <openssl/crypto.h>
34
#include <crypto/cryptlib.h>
35
#include <crypto/sparse_array.h>
36
#include "internal/cryptlib.h"
37
#include "internal/threads_common.h"
38
#include "internal/rcu.h"
39
#ifdef REPORT_RWLOCK_CONTENTION
40
#include <fcntl.h>
41
#include <stdbool.h>
42
#include <sys/syscall.h>
43
#include <sys/uio.h>
44
#include "internal/time.h"
45
#endif
46
#include "rcu_internal.h"
47
48
#if defined(__SANITIZE_THREAD__)
49
#define TSAN_FAKE_UNLOCK(x)          \
50
    __tsan_mutex_pre_unlock((x), 0); \
51
    __tsan_mutex_post_unlock((x), 0)
52
53
#define TSAN_FAKE_LOCK(x)          \
54
    __tsan_mutex_pre_lock((x), 0); \
55
    __tsan_mutex_post_lock((x), 0, 0)
56
#else
57
#define TSAN_FAKE_UNLOCK(x)
58
#define TSAN_FAKE_LOCK(x)
59
#endif
60
61
#if defined(__sun)
62
#include <atomic.h>
63
#endif
64
65
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS)
66
67
#if defined(OPENSSL_SYS_UNIX)
68
#include <sys/types.h>
69
#include <unistd.h>
70
#endif
71
72
#include <assert.h>
73
74
/*
75
 * The Non-Stop KLT thread model currently seems broken in its rwlock
76
 * implementation
77
 * Likewise is there a problem with the glibc implementation on riscv.
78
 */
79
#if defined(PTHREAD_RWLOCK_INITIALIZER) && !defined(_KLT_MODEL_) && !defined(_PUT_MODEL_) \
80
    && !defined(__riscv)
81
#define USE_RWLOCK
82
#endif
83
84
/*
85
 * For all GNU/clang atomic builtins, we also need fallbacks, to cover all
86
 * other compilers.
87
88
 * Unfortunately, we can't do that with some "generic type", because there's no
89
 * guarantee that the chosen generic type is large enough to cover all cases.
90
 * Therefore, we implement fallbacks for each applicable type, with composed
91
 * names that include the type they handle.
92
 *
93
 * (an anecdote: we previously tried to use |void *| as the generic type, with
94
 * the thought that the pointer itself is the largest type.  However, this is
95
 * not true on 32-bit pointer platforms, as a |uint64_t| is twice as large)
96
 *
97
 * All applicable ATOMIC_ macros take the intended type as first parameter, so
98
 * they can map to the correct fallback function.  In the GNU/clang case, that
99
 * parameter is simply ignored.
100
 */
101
102
/*
103
 * Internal types used with the ATOMIC_ macros, to make it possible to compose
104
 * fallback function names.
105
 */
106
typedef void *pvoid;
107
108
#if defined(OSSL_USE_GCC_ATOMICS)
109
421k
#define ATOMIC_LOAD_N(t, p, o) __atomic_load_n(p, o)
110
0
#define ATOMIC_STORE_N(t, p, v, o) __atomic_store_n(p, v, o)
111
6.41k
#define ATOMIC_STORE(t, p, v, o) __atomic_store(p, v, o)
112
0
#define ATOMIC_ADD_FETCH(p, v, o) __atomic_add_fetch(p, v, o)
113
0
#define ATOMIC_SUB_FETCH(p, v, o) __atomic_sub_fetch(p, v, o)
114
#else
115
static pthread_mutex_t atomic_sim_lock = PTHREAD_MUTEX_INITIALIZER;
116
117
#define IMPL_fallback_atomic_load_n(t)                    \
118
    static ossl_inline t fallback_atomic_load_n_##t(t *p) \
119
    {                                                     \
120
        t ret;                                            \
121
                                                          \
122
        pthread_mutex_lock(&atomic_sim_lock);             \
123
        ret = *p;                                         \
124
        pthread_mutex_unlock(&atomic_sim_lock);           \
125
        return ret;                                       \
126
    }
127
IMPL_fallback_atomic_load_n(uint32_t)
128
    IMPL_fallback_atomic_load_n(uint64_t)
129
        IMPL_fallback_atomic_load_n(pvoid)
130
131
#define ATOMIC_LOAD_N(t, p, o) fallback_atomic_load_n_##t(p)
132
133
#define IMPL_fallback_atomic_store_n(t)                         \
134
    static ossl_inline t fallback_atomic_store_n_##t(t *p, t v) \
135
    {                                                           \
136
        t ret;                                                  \
137
                                                                \
138
        pthread_mutex_lock(&atomic_sim_lock);                   \
139
        ret = *p;                                               \
140
        *p = v;                                                 \
141
        pthread_mutex_unlock(&atomic_sim_lock);                 \
142
        return ret;                                             \
143
    }
144
            IMPL_fallback_atomic_store_n(uint32_t)
145
146
#define ATOMIC_STORE_N(t, p, v, o) fallback_atomic_store_n_##t(p, v)
147
148
#define IMPL_fallback_atomic_store(t)                             \
149
    static ossl_inline void fallback_atomic_store_##t(t *p, t *v) \
150
    {                                                             \
151
        pthread_mutex_lock(&atomic_sim_lock);                     \
152
        *p = *v;                                                  \
153
        pthread_mutex_unlock(&atomic_sim_lock);                   \
154
    }
155
                IMPL_fallback_atomic_store(pvoid)
156
157
#define ATOMIC_STORE(t, p, v, o) fallback_atomic_store_##t(p, v)
158
159
    /*
160
     * The fallbacks that follow don't need any per type implementation, as
161
     * they are designed for uint64_t only.  If there comes a time when multiple
162
     * types need to be covered, it's relatively easy to refactor them the same
163
     * way as the fallbacks above.
164
     */
165
166
    static ossl_inline uint64_t fallback_atomic_add_fetch(uint64_t *p, uint64_t v)
167
{
168
    uint64_t ret;
169
170
    pthread_mutex_lock(&atomic_sim_lock);
171
    *p += v;
172
    ret = *p;
173
    pthread_mutex_unlock(&atomic_sim_lock);
174
    return ret;
175
}
176
177
#define ATOMIC_ADD_FETCH(p, v, o) fallback_atomic_add_fetch(p, v)
178
179
static ossl_inline uint64_t fallback_atomic_sub_fetch(uint64_t *p, uint64_t v)
180
{
181
    uint64_t ret;
182
183
    pthread_mutex_lock(&atomic_sim_lock);
184
    *p -= v;
185
    ret = *p;
186
    pthread_mutex_unlock(&atomic_sim_lock);
187
    return ret;
188
}
189
190
#define ATOMIC_SUB_FETCH(p, v, o) fallback_atomic_sub_fetch(p, v)
191
#endif
192
193
/*
194
 * This is the core of an rcu lock. It tracks the readers and writers for the
195
 * current quiescence point for a given lock. Users is the 64 bit value that
196
 * stores the READERS/ID as defined above
197
 *
198
 */
199
struct rcu_qp {
200
    uint64_t users;
201
};
202
203
struct thread_qp {
204
    struct rcu_qp *qp;
205
    unsigned int depth;
206
    CRYPTO_RCU_LOCK *lock;
207
};
208
209
0
#define MAX_QPS 10
210
/*
211
 * This is the per thread tracking data
212
 * that is assigned to each thread participating
213
 * in an rcu qp
214
 *
215
 * qp points to the qp that it last acquired
216
 *
217
 */
218
struct rcu_thr_data {
219
    struct thread_qp thread_qps[MAX_QPS];
220
};
221
222
/*
223
 * This is the internal version of a CRYPTO_RCU_LOCK
224
 * it is cast from CRYPTO_RCU_LOCK
225
 */
226
struct rcu_lock_st {
227
    /* Callbacks to call for next ossl_synchronize_rcu */
228
    struct rcu_cb_item *cb_items;
229
230
    /* The context we are being created against */
231
    OSSL_LIB_CTX *ctx;
232
233
    /* Array of quiescent points for synchronization */
234
    struct rcu_qp *qp_group;
235
236
    /* rcu generation counter for in-order retirement */
237
    uint32_t id_ctr;
238
239
    /* Number of elements in qp_group array */
240
    uint32_t group_count;
241
242
    /* Index of the current qp in the qp_group array */
243
    uint32_t reader_idx;
244
245
    /* value of the next id_ctr value to be retired */
246
    uint32_t next_to_retire;
247
248
    /* index of the next free rcu_qp in the qp_group */
249
    uint32_t current_alloc_idx;
250
251
    /* number of qp's in qp_group array currently being retired */
252
    uint32_t writers_alloced;
253
254
    /* lock protecting write side operations */
255
    pthread_mutex_t write_lock;
256
257
    /* lock protecting updates to writers_alloced/current_alloc_idx */
258
    pthread_mutex_t alloc_lock;
259
260
    /* signal to wake threads waiting on alloc_lock */
261
    pthread_cond_t alloc_signal;
262
263
    /* lock to enforce in-order retirement */
264
    pthread_mutex_t prior_lock;
265
266
    /* signal to wake threads waiting on prior_lock */
267
    pthread_cond_t prior_signal;
268
};
269
270
/* Read side acquisition of the current qp */
271
static struct rcu_qp *get_hold_current_qp(struct rcu_lock_st *lock)
272
0
{
273
0
    uint32_t qp_idx;
274
275
    /* get the current qp index */
276
0
    for (;;) {
277
0
        qp_idx = ATOMIC_LOAD_N(uint32_t, &lock->reader_idx, __ATOMIC_RELAXED);
278
279
        /*
280
         * Notes on use of __ATOMIC_ACQUIRE
281
         * We need to ensure the following:
282
         * 1) That subsequent operations aren't optimized by hoisting them above
283
         * this operation.  Specifically, we don't want the below re-load of
284
         * qp_idx to get optimized away
285
         * 2) We want to ensure that any updating of reader_idx on the write side
286
         * of the lock is flushed from a local cpu cache so that we see any
287
         * updates prior to the load.  This is a non-issue on cache coherent
288
         * systems like x86, but is relevant on other arches
289
         */
290
0
        ATOMIC_ADD_FETCH(&lock->qp_group[qp_idx].users, (uint64_t)1,
291
0
            __ATOMIC_ACQUIRE);
292
293
        /* if the idx hasn't changed, we're good, else try again */
294
0
        if (qp_idx == ATOMIC_LOAD_N(uint32_t, &lock->reader_idx, __ATOMIC_ACQUIRE))
295
0
            break;
296
297
0
        ATOMIC_SUB_FETCH(&lock->qp_group[qp_idx].users, (uint64_t)1,
298
0
            __ATOMIC_RELAXED);
299
0
    }
300
301
0
    return &lock->qp_group[qp_idx];
302
0
}
303
304
static void ossl_rcu_free_local_data(void *arg)
305
0
{
306
0
    OSSL_LIB_CTX *ctx = arg;
307
0
    struct rcu_thr_data *data = CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_RCU_KEY, ctx);
308
309
0
    CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_RCU_KEY, ctx, NULL);
310
0
    OPENSSL_free(data);
311
0
}
312
313
int ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock)
314
0
{
315
0
    struct rcu_thr_data *data;
316
0
    int i, available_qp = -1;
317
318
    /*
319
     * we're going to access current_qp here so ask the
320
     * processor to fetch it
321
     */
322
0
    data = CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_RCU_KEY, lock->ctx);
323
324
0
    if (data == NULL) {
325
0
        data = OPENSSL_zalloc(sizeof(*data));
326
0
        if (data == NULL)
327
0
            return 0;
328
329
0
        if (!CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_RCU_KEY, lock->ctx, data)) {
330
0
            OPENSSL_free(data);
331
0
            return 0;
332
0
        }
333
0
        if (!ossl_init_thread_start(NULL, lock->ctx, ossl_rcu_free_local_data)) {
334
0
            OPENSSL_free(data);
335
0
            CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_RCU_KEY, lock->ctx, NULL);
336
0
            return 0;
337
0
        }
338
0
    }
339
340
0
    for (i = 0; i < MAX_QPS; i++) {
341
0
        if (data->thread_qps[i].qp == NULL && available_qp == -1)
342
0
            available_qp = i;
343
        /* If we have a hold on this lock already, we're good */
344
0
        if (data->thread_qps[i].lock == lock) {
345
0
            data->thread_qps[i].depth++;
346
0
            return 1;
347
0
        }
348
0
    }
349
350
    /*
351
     * if we get here, then we don't have a hold on this lock yet
352
     */
353
0
    assert(available_qp != -1);
354
355
0
    data->thread_qps[available_qp].qp = get_hold_current_qp(lock);
356
0
    data->thread_qps[available_qp].depth = 1;
357
0
    data->thread_qps[available_qp].lock = lock;
358
0
    return 1;
359
0
}
360
361
void ossl_rcu_read_unlock(CRYPTO_RCU_LOCK *lock)
362
0
{
363
0
    int i;
364
0
    struct rcu_thr_data *data = CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_RCU_KEY, lock->ctx);
365
0
    uint64_t ret;
366
367
0
    assert(data != NULL);
368
369
0
    for (i = 0; i < MAX_QPS; i++) {
370
0
        if (data->thread_qps[i].lock == lock) {
371
            /*
372
             * we have to use __ATOMIC_RELEASE here
373
             * to ensure that all preceding read instructions complete
374
             * before the decrement is visible to ossl_synchronize_rcu
375
             */
376
0
            data->thread_qps[i].depth--;
377
0
            if (data->thread_qps[i].depth == 0) {
378
0
                ret = ATOMIC_SUB_FETCH(&data->thread_qps[i].qp->users,
379
0
                    (uint64_t)1, __ATOMIC_RELEASE);
380
0
                OPENSSL_assert(ret != UINT64_MAX);
381
0
                data->thread_qps[i].qp = NULL;
382
0
                data->thread_qps[i].lock = NULL;
383
0
            }
384
0
            return;
385
0
        }
386
0
    }
387
    /*
388
     * If we get here, we're trying to unlock a lock that we never acquired -
389
     * that's fatal.
390
     */
391
0
    assert(0);
392
0
}
393
394
/*
395
 * Write side allocation routine to get the current qp
396
 * and replace it with a new one
397
 */
398
static struct rcu_qp *update_qp(CRYPTO_RCU_LOCK *lock, uint32_t *curr_id)
399
0
{
400
0
    uint32_t current_idx;
401
402
0
    pthread_mutex_lock(&lock->alloc_lock);
403
404
    /*
405
     * we need at least one qp to be available with one
406
     * left over, so that readers can start working on
407
     * one that isn't yet being waited on
408
     */
409
0
    while (lock->group_count - lock->writers_alloced < 2)
410
        /* we have to wait for one to be free */
411
0
        pthread_cond_wait(&lock->alloc_signal, &lock->alloc_lock);
412
413
0
    current_idx = lock->current_alloc_idx;
414
415
    /* Allocate the qp */
416
0
    lock->writers_alloced++;
417
418
    /* increment the allocation index */
419
0
    lock->current_alloc_idx = (lock->current_alloc_idx + 1) % lock->group_count;
420
421
0
    *curr_id = lock->id_ctr;
422
0
    lock->id_ctr++;
423
424
    /*
425
     * make the current state of everything visible by this release
426
     * when get_hold_current_qp acquires the next qp
427
     */
428
0
    ATOMIC_STORE_N(uint32_t, &lock->reader_idx, lock->current_alloc_idx,
429
0
        __ATOMIC_RELEASE);
430
431
    /*
432
     * this should make sure that the new value of reader_idx is visible in
433
     * get_hold_current_qp, directly after incrementing the users count
434
     */
435
0
    ATOMIC_ADD_FETCH(&lock->qp_group[current_idx].users, (uint64_t)0,
436
0
        __ATOMIC_RELEASE);
437
438
    /* wake up any waiters */
439
0
    pthread_cond_signal(&lock->alloc_signal);
440
0
    pthread_mutex_unlock(&lock->alloc_lock);
441
0
    return &lock->qp_group[current_idx];
442
0
}
443
444
static void retire_qp(CRYPTO_RCU_LOCK *lock, struct rcu_qp *qp)
445
0
{
446
0
    pthread_mutex_lock(&lock->alloc_lock);
447
0
    lock->writers_alloced--;
448
0
    pthread_cond_signal(&lock->alloc_signal);
449
0
    pthread_mutex_unlock(&lock->alloc_lock);
450
0
}
451
452
static struct rcu_qp *allocate_new_qp_group(CRYPTO_RCU_LOCK *lock,
453
    uint32_t count)
454
16
{
455
16
    struct rcu_qp *new = OPENSSL_calloc(count, sizeof(*new));
456
457
16
    lock->group_count = count;
458
16
    return new;
459
16
}
460
461
void ossl_rcu_write_lock(CRYPTO_RCU_LOCK *lock)
462
0
{
463
0
    pthread_mutex_lock(&lock->write_lock);
464
0
    TSAN_FAKE_UNLOCK(&lock->write_lock);
465
0
}
466
467
void ossl_rcu_write_unlock(CRYPTO_RCU_LOCK *lock)
468
0
{
469
0
    TSAN_FAKE_LOCK(&lock->write_lock);
470
0
    pthread_mutex_unlock(&lock->write_lock);
471
0
}
472
473
void ossl_synchronize_rcu(CRYPTO_RCU_LOCK *lock)
474
0
{
475
0
    struct rcu_qp *qp;
476
0
    uint64_t count;
477
0
    uint32_t curr_id;
478
0
    struct rcu_cb_item *cb_items, *tmpcb;
479
480
0
    pthread_mutex_lock(&lock->write_lock);
481
0
    cb_items = lock->cb_items;
482
0
    lock->cb_items = NULL;
483
0
    pthread_mutex_unlock(&lock->write_lock);
484
485
0
    qp = update_qp(lock, &curr_id);
486
487
    /* retire in order */
488
0
    pthread_mutex_lock(&lock->prior_lock);
489
0
    while (lock->next_to_retire != curr_id)
490
0
        pthread_cond_wait(&lock->prior_signal, &lock->prior_lock);
491
492
    /*
493
     * wait for the reader count to reach zero
494
     * Note the use of __ATOMIC_ACQUIRE here to ensure that any
495
     * prior __ATOMIC_RELEASE write operation in ossl_rcu_read_unlock
496
     * is visible prior to our read
497
     * however this is likely just necessary to silence a tsan warning
498
     * because the read side should not do any write operation
499
     * outside the atomic itself
500
     */
501
0
    do {
502
0
        count = ATOMIC_LOAD_N(uint64_t, &qp->users, __ATOMIC_ACQUIRE);
503
0
    } while (count != (uint64_t)0);
504
505
0
    lock->next_to_retire++;
506
0
    pthread_cond_broadcast(&lock->prior_signal);
507
0
    pthread_mutex_unlock(&lock->prior_lock);
508
509
0
    retire_qp(lock, qp);
510
511
    /* handle any callbacks that we have */
512
0
    while (cb_items != NULL) {
513
0
        tmpcb = cb_items;
514
0
        cb_items = cb_items->next;
515
0
        tmpcb->fn(tmpcb->data);
516
0
        OPENSSL_free(tmpcb);
517
0
    }
518
0
}
519
520
CRYPTO_RCU_CB_ITEM *ossl_rcu_cb_item_new(void)
521
0
{
522
0
    return OPENSSL_zalloc(sizeof(CRYPTO_RCU_CB_ITEM));
523
0
}
524
525
void ossl_rcu_cb_item_free(CRYPTO_RCU_CB_ITEM *item)
526
0
{
527
0
    OPENSSL_free(item);
528
0
}
529
530
/*
531
 * Note: This call assumes its made under the protection of
532
 * ossl_rcu_write_lock
533
 */
534
void ossl_rcu_call(CRYPTO_RCU_LOCK *lock, CRYPTO_RCU_CB_ITEM *item,
535
    rcu_cb_fn cb, void *data)
536
0
{
537
0
    item->fn = cb;
538
0
    item->data = data;
539
0
    item->next = lock->cb_items;
540
0
    lock->cb_items = item;
541
0
}
542
543
void *ossl_rcu_uptr_deref(void **p)
544
421k
{
545
421k
    return ATOMIC_LOAD_N(pvoid, p, __ATOMIC_ACQUIRE);
546
421k
}
547
548
void ossl_rcu_assign_uptr(void **p, void **v)
549
6.41k
{
550
6.41k
    ATOMIC_STORE(pvoid, p, v, __ATOMIC_RELEASE);
551
6.41k
}
552
553
CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx)
554
16
{
555
16
    struct rcu_lock_st *new;
556
16
    pthread_mutex_t *mutexes[3] = { NULL };
557
16
    pthread_cond_t *conds[2] = { NULL };
558
16
    int i;
559
560
    /*
561
     * We need a minimum of 2 qp's
562
     */
563
16
    if (num_writers < 2)
564
16
        num_writers = 2;
565
566
16
    ctx = ossl_lib_ctx_get_concrete(ctx);
567
16
    if (ctx == NULL)
568
0
        return 0;
569
570
16
    new = OPENSSL_zalloc(sizeof(*new));
571
16
    if (new == NULL)
572
0
        return NULL;
573
574
16
    new->ctx = ctx;
575
16
    i = 0;
576
16
    mutexes[i] = pthread_mutex_init(&new->write_lock, NULL) == 0 ? &new->write_lock : NULL;
577
16
    if (mutexes[i++] == NULL)
578
0
        goto err;
579
16
    mutexes[i] = pthread_mutex_init(&new->prior_lock, NULL) == 0 ? &new->prior_lock : NULL;
580
16
    if (mutexes[i++] == NULL)
581
0
        goto err;
582
16
    mutexes[i] = pthread_mutex_init(&new->alloc_lock, NULL) == 0 ? &new->alloc_lock : NULL;
583
16
    if (mutexes[i++] == NULL)
584
0
        goto err;
585
16
    conds[i - 3] = pthread_cond_init(&new->prior_signal, NULL) == 0 ? &new->prior_signal : NULL;
586
16
    if (conds[i - 3] == NULL)
587
0
        goto err;
588
16
    i++;
589
16
    conds[i - 3] = pthread_cond_init(&new->alloc_signal, NULL) == 0 ? &new->alloc_signal : NULL;
590
16
    if (conds[i - 3] == NULL)
591
0
        goto err;
592
16
    i++;
593
16
    new->qp_group = allocate_new_qp_group(new, num_writers);
594
16
    if (new->qp_group == NULL)
595
0
        goto err;
596
597
16
    return new;
598
599
0
err:
600
0
    for (i = 0; i < 3; i++)
601
0
        if (mutexes[i] != NULL)
602
0
            pthread_mutex_destroy(mutexes[i]);
603
0
    for (i = 0; i < 2; i++)
604
0
        if (conds[i] != NULL)
605
0
            pthread_cond_destroy(conds[i]);
606
0
    OPENSSL_free(new->qp_group);
607
0
    OPENSSL_free(new);
608
0
    return NULL;
609
16
}
610
611
void ossl_rcu_lock_free(CRYPTO_RCU_LOCK *lock)
612
0
{
613
0
    struct rcu_lock_st *rlock = (struct rcu_lock_st *)lock;
614
615
0
    if (lock == NULL)
616
0
        return;
617
618
    /* make sure we're synchronized */
619
0
    ossl_synchronize_rcu(rlock);
620
621
0
    OPENSSL_free(rlock->qp_group);
622
    /*
623
     * Some targets (BSD) allocate heap when initializing
624
     * a mutex or condition, to prevent leaks, those need
625
     * to be destroyed here
626
     */
627
0
    pthread_mutex_destroy(&rlock->write_lock);
628
0
    pthread_mutex_destroy(&rlock->prior_lock);
629
0
    pthread_mutex_destroy(&rlock->alloc_lock);
630
0
    pthread_cond_destroy(&rlock->prior_signal);
631
0
    pthread_cond_destroy(&rlock->alloc_signal);
632
633
    /* There should only be a single qp left now */
634
0
    OPENSSL_free(rlock);
635
0
}
636
637
#ifdef REPORT_RWLOCK_CONTENTION
638
/*
639
 * Normally we would use a BIO here to do this, but we create locks during
640
 * library initialization, and creating a bio too early, creates a recursive set
641
 * of stack calls that leads us to call CRYPTO_thread_run_once while currently
642
 * executing the init routine for various run_once functions, which leads to
643
 * deadlock.  Avoid that by just using a FILE pointer.  Also note that we
644
 * directly use a pthread_mutex_t to protect access from multiple threads
645
 * to the contention log file.  We do this because we want to avoid use
646
 * of the CRYPTO_THREAD api so as to prevent recursive blocking reports.
647
 */
648
static CRYPTO_ONCE init_contention_data_flag = CRYPTO_ONCE_STATIC_INIT;
649
pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
650
CRYPTO_THREAD_LOCAL thread_contention_data;
651
652
struct stack_info {
653
    unsigned int nptrs;
654
    int write;
655
    OSSL_TIME start;
656
    OSSL_TIME duration;
657
    char **strings;
658
};
659
660
#define STACKS_COUNT 32
661
#define BT_BUF_SIZE 1024
662
struct stack_traces {
663
    int fd;
664
    int lock_depth;
665
    size_t idx;
666
    struct stack_info stacks[STACKS_COUNT];
667
};
668
669
/* The glibc gettid() definition presents only since 2.30. */
670
static ossl_inline pid_t get_tid(void)
671
{
672
#ifdef OPENSSL_SYS_MACOSX
673
    /*
674
     * MACOS has the gettid call, but it does something completely different
675
     * here than on other unixes.  Specifically it returns the uid of the calling thread
676
     * (if set), or -1.  We need to use a MACOS specific call to get the thread id here
677
     */
678
    uint64_t tid;
679
680
    pthread_threadid_np(NULL, &tid);
681
    return (pid_t)tid;
682
#else
683
    return syscall(SYS_gettid);
684
#endif
685
}
686
687
#ifdef FIPS_MODULE
688
#define FIPS_SFX "-fips"
689
#else
690
#define FIPS_SFX ""
691
#endif
692
static void *init_contention_data(void)
693
{
694
    struct stack_traces *traces;
695
    char fname_fmt[] = "lock-contention-log" FIPS_SFX ".%d.txt";
696
    char fname[sizeof(fname_fmt) + sizeof(int) * 3];
697
698
    traces = OPENSSL_zalloc(sizeof(struct stack_traces));
699
700
    snprintf(fname, sizeof(fname), fname_fmt, get_tid());
701
702
    traces->fd = open(fname, O_WRONLY | O_APPEND | O_CLOEXEC | O_CREAT, 0600);
703
704
    return traces;
705
}
706
707
static void destroy_contention_data(void *data)
708
{
709
    struct stack_traces *st = data;
710
711
    close(st->fd);
712
    OPENSSL_free(data);
713
}
714
715
static void init_contention_data_once(void)
716
{
717
    /*
718
     * Create a thread local key here to store our list of stack traces
719
     * to be printed when we unlock the lock we are holding
720
     */
721
    CRYPTO_THREAD_init_local(&thread_contention_data, destroy_contention_data);
722
    return;
723
}
724
725
static struct stack_traces *get_stack_traces(bool init)
726
{
727
    struct stack_traces *traces = CRYPTO_THREAD_get_local(&thread_contention_data);
728
729
    if (!traces && init) {
730
        traces = init_contention_data();
731
        CRYPTO_THREAD_set_local(&thread_contention_data, traces);
732
    }
733
734
    return traces;
735
}
736
737
static void print_stack_traces(struct stack_traces *traces)
738
{
739
    unsigned int j;
740
    struct iovec *iov;
741
    int iovcnt;
742
743
    while (traces != NULL && traces->idx >= 1) {
744
        traces->idx--;
745
        dprintf(traces->fd,
746
            "lock blocked on %s for %zu usec at time %zu tid %d\n",
747
            traces->stacks[traces->idx].write == 1 ? "WRITE" : "READ",
748
            ossl_time2us(traces->stacks[traces->idx].duration),
749
            ossl_time2us(traces->stacks[traces->idx].start),
750
            get_tid());
751
        if (traces->stacks[traces->idx].strings != NULL) {
752
            static const char lf = '\n';
753
754
            iovcnt = traces->stacks[traces->idx].nptrs * 2 + 1;
755
            iov = alloca(iovcnt * sizeof(*iov));
756
            for (j = 0; j < traces->stacks[traces->idx].nptrs; j++) {
757
                iov[2 * j].iov_base = traces->stacks[traces->idx].strings[j];
758
                iov[2 * j].iov_len = strlen(traces->stacks[traces->idx].strings[j]);
759
                iov[2 * j + 1].iov_base = (char *)&lf;
760
                iov[2 * j + 1].iov_len = 1;
761
            }
762
            iov[traces->stacks[traces->idx].nptrs * 2].iov_base = (char *)&lf;
763
            iov[traces->stacks[traces->idx].nptrs * 2].iov_len = 1;
764
        } else {
765
            static const char no_bt[] = "No stack trace available\n\n";
766
767
            iovcnt = 1;
768
            iov = alloca(iovcnt * sizeof(*iov));
769
            iov[0].iov_base = (char *)no_bt;
770
            iov[0].iov_len = sizeof(no_bt) - 1;
771
        }
772
        writev(traces->fd, iov, iovcnt);
773
        free(traces->stacks[traces->idx].strings);
774
    }
775
}
776
777
static ossl_inline void ossl_init_rwlock_contention_data(void)
778
{
779
    CRYPTO_THREAD_run_once(&init_contention_data_flag, init_contention_data_once);
780
}
781
782
static int record_lock_contention(pthread_rwlock_t *lock,
783
    struct stack_traces *traces, bool write)
784
{
785
    void *buffer[BT_BUF_SIZE];
786
    OSSL_TIME start, end;
787
    int ret;
788
789
    start = ossl_time_now();
790
    ret = (write ? pthread_rwlock_wrlock : pthread_rwlock_rdlock)(lock);
791
    if (ret)
792
        return ret;
793
    end = ossl_time_now();
794
    traces->stacks[traces->idx].nptrs = backtrace(buffer, BT_BUF_SIZE);
795
    traces->stacks[traces->idx].strings = backtrace_symbols(buffer,
796
        traces->stacks[traces->idx].nptrs);
797
    traces->stacks[traces->idx].duration = ossl_time_subtract(end, start);
798
    traces->stacks[traces->idx].start = start;
799
    traces->stacks[traces->idx].write = write;
800
    traces->idx++;
801
    if (traces->idx >= STACKS_COUNT) {
802
        fprintf(stderr, "STACK RECORD OVERFLOW!\n");
803
        print_stack_traces(traces);
804
    }
805
806
    return 0;
807
}
808
809
static ossl_inline int ossl_rwlock_rdlock(pthread_rwlock_t *lock)
810
{
811
    struct stack_traces *traces = get_stack_traces(true);
812
813
    if (ossl_unlikely(traces == NULL))
814
        return ENOMEM;
815
816
    traces->lock_depth++;
817
    if (pthread_rwlock_tryrdlock(lock)) {
818
        int ret = record_lock_contention(lock, traces, false);
819
820
        if (ret)
821
            traces->lock_depth--;
822
823
        return ret;
824
    }
825
826
    return 0;
827
}
828
829
static ossl_inline int ossl_rwlock_wrlock(pthread_rwlock_t *lock)
830
{
831
    struct stack_traces *traces = get_stack_traces(true);
832
833
    if (ossl_unlikely(traces == NULL))
834
        return ENOMEM;
835
836
    traces->lock_depth++;
837
    if (pthread_rwlock_trywrlock(lock)) {
838
        int ret = record_lock_contention(lock, traces, true);
839
840
        if (ret)
841
            traces->lock_depth--;
842
843
        return ret;
844
    }
845
846
    return 0;
847
}
848
849
static ossl_inline int ossl_rwlock_unlock(pthread_rwlock_t *lock)
850
{
851
    int ret;
852
853
    ret = pthread_rwlock_unlock(lock);
854
    if (ret)
855
        return ret;
856
857
    {
858
        struct stack_traces *traces = get_stack_traces(false);
859
860
        if (traces != NULL) {
861
            traces->lock_depth--;
862
            assert(traces->lock_depth >= 0);
863
            if (traces->lock_depth == 0)
864
                print_stack_traces(traces);
865
        }
866
    }
867
868
    return 0;
869
}
870
871
#else /* !REPORT_RWLOCK_CONTENTION */
872
873
#if defined(USE_RWLOCK)
874
static ossl_inline void ossl_init_rwlock_contention_data(void)
875
52.2k
{
876
52.2k
}
877
878
static ossl_inline int ossl_rwlock_rdlock(pthread_rwlock_t *rwlock)
879
327k
{
880
327k
    return pthread_rwlock_rdlock(rwlock);
881
327k
}
882
883
static ossl_inline int ossl_rwlock_wrlock(pthread_rwlock_t *rwlock)
884
24.6k
{
885
24.6k
    return pthread_rwlock_wrlock(rwlock);
886
24.6k
}
887
888
static ossl_inline int ossl_rwlock_unlock(pthread_rwlock_t *rwlock)
889
352k
{
890
352k
    return pthread_rwlock_unlock(rwlock);
891
352k
}
892
#endif /* USE_RWLOCK */
893
#endif /* REPORT_RWLOCK_CONTENTION */
894
895
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
896
52.2k
{
897
52.2k
#ifdef USE_RWLOCK
898
52.2k
    CRYPTO_RWLOCK *lock;
899
900
52.2k
    ossl_init_rwlock_contention_data();
901
902
52.2k
    if ((lock = OPENSSL_zalloc(sizeof(pthread_rwlock_t))) == NULL)
903
        /* Don't set error, to avoid recursion blowup. */
904
0
        return NULL;
905
906
52.2k
    if (pthread_rwlock_init(lock, NULL) != 0) {
907
0
        OPENSSL_free(lock);
908
0
        return NULL;
909
0
    }
910
#else
911
    pthread_mutexattr_t attr;
912
    CRYPTO_RWLOCK *lock;
913
914
    if ((lock = OPENSSL_zalloc(sizeof(pthread_mutex_t))) == NULL)
915
        /* Don't set error, to avoid recursion blowup. */
916
        return NULL;
917
918
    /*
919
     * We don't use recursive mutexes, but try to catch errors if we do.
920
     */
921
    pthread_mutexattr_init(&attr);
922
#if !defined(__TANDEM) && !defined(_SPT_MODEL_)
923
#if !defined(NDEBUG) && !defined(OPENSSL_NO_MUTEX_ERRORCHECK)
924
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
925
#endif
926
#else
927
    /* The SPT Thread Library does not define MUTEX attributes. */
928
#endif
929
930
    if (pthread_mutex_init(lock, &attr) != 0) {
931
        pthread_mutexattr_destroy(&attr);
932
        OPENSSL_free(lock);
933
        return NULL;
934
    }
935
936
    pthread_mutexattr_destroy(&attr);
937
#endif
938
939
52.2k
    return lock;
940
52.2k
}
941
942
__owur int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
943
327k
{
944
327k
#ifdef USE_RWLOCK
945
327k
    if (!ossl_assert(ossl_rwlock_rdlock(lock) == 0))
946
0
        return 0;
947
#else
948
    if (pthread_mutex_lock(lock) != 0) {
949
        assert(errno != EDEADLK && errno != EBUSY);
950
        return 0;
951
    }
952
#endif
953
954
327k
    return 1;
955
327k
}
956
957
__owur int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
958
24.6k
{
959
24.6k
#ifdef USE_RWLOCK
960
24.6k
    if (!ossl_assert(ossl_rwlock_wrlock(lock) == 0))
961
0
        return 0;
962
#else
963
    if (pthread_mutex_lock(lock) != 0) {
964
        assert(errno != EDEADLK && errno != EBUSY);
965
        return 0;
966
    }
967
#endif
968
969
24.6k
    return 1;
970
24.6k
}
971
972
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
973
352k
{
974
352k
#ifdef USE_RWLOCK
975
352k
    if (ossl_rwlock_unlock(lock) != 0)
976
0
        return 0;
977
#else
978
    if (pthread_mutex_unlock(lock) != 0) {
979
        assert(errno != EPERM);
980
        return 0;
981
    }
982
#endif
983
984
352k
    return 1;
985
352k
}
986
987
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
988
51.6k
{
989
51.6k
    if (lock == NULL)
990
0
        return;
991
992
51.6k
#ifdef USE_RWLOCK
993
51.6k
    pthread_rwlock_destroy(lock);
994
#else
995
    pthread_mutex_destroy(lock);
996
#endif
997
51.6k
    OPENSSL_free(lock);
998
999
51.6k
    return;
1000
51.6k
}
1001
1002
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
1003
1.21M
{
1004
1.21M
    if (ossl_unlikely(pthread_once(once, init) != 0))
1005
0
        return 0;
1006
1007
1.21M
    return 1;
1008
1.21M
}
1009
1010
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
1011
64
{
1012
64
    if (pthread_key_create(key, cleanup) != 0)
1013
0
        return 0;
1014
1015
64
    return 1;
1016
64
}
1017
1018
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
1019
549k
{
1020
549k
    return pthread_getspecific(*key);
1021
549k
}
1022
1023
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
1024
48
{
1025
48
    if (pthread_setspecific(*key, val) != 0)
1026
0
        return 0;
1027
1028
48
    return 1;
1029
48
}
1030
1031
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
1032
0
{
1033
0
    if (pthread_key_delete(*key) != 0)
1034
0
        return 0;
1035
1036
0
    return 1;
1037
0
}
1038
1039
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
1040
0
{
1041
0
    return pthread_self();
1042
0
}
1043
1044
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
1045
0
{
1046
0
    return pthread_equal(a, b);
1047
0
}
1048
1049
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
1050
122
{
1051
122
#if defined(OSSL_USE_GCC_ATOMICS)
1052
122
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1053
122
        *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL);
1054
122
        return 1;
1055
122
    }
1056
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1057
    /* This will work for all future Solaris versions. */
1058
    if (ret != NULL) {
1059
        *ret = atomic_add_int_nv((volatile unsigned int *)val, amount);
1060
        return 1;
1061
    }
1062
#endif
1063
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1064
0
        return 0;
1065
1066
0
    *val += amount;
1067
0
    *ret = *val;
1068
1069
0
    if (!CRYPTO_THREAD_unlock(lock))
1070
0
        return 0;
1071
1072
0
    return 1;
1073
0
}
1074
1075
int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret,
1076
    CRYPTO_RWLOCK *lock)
1077
0
{
1078
0
#if defined(OSSL_USE_GCC_ATOMICS)
1079
0
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1080
0
        *ret = __atomic_add_fetch(val, op, __ATOMIC_ACQ_REL);
1081
0
        return 1;
1082
0
    }
1083
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1084
    /* This will work for all future Solaris versions. */
1085
    if (ret != NULL) {
1086
        *ret = atomic_add_64_nv(val, op);
1087
        return 1;
1088
    }
1089
#endif
1090
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1091
0
        return 0;
1092
0
    *val += op;
1093
0
    *ret = *val;
1094
1095
0
    if (!CRYPTO_THREAD_unlock(lock))
1096
0
        return 0;
1097
1098
0
    return 1;
1099
0
}
1100
1101
int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret,
1102
    CRYPTO_RWLOCK *lock)
1103
0
{
1104
0
#if defined(OSSL_USE_GCC_ATOMICS)
1105
0
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1106
0
        *ret = __atomic_and_fetch(val, op, __ATOMIC_ACQ_REL);
1107
0
        return 1;
1108
0
    }
1109
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1110
    /* This will work for all future Solaris versions. */
1111
    if (ret != NULL) {
1112
        *ret = atomic_and_64_nv(val, op);
1113
        return 1;
1114
    }
1115
#endif
1116
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1117
0
        return 0;
1118
0
    *val &= op;
1119
0
    *ret = *val;
1120
1121
0
    if (!CRYPTO_THREAD_unlock(lock))
1122
0
        return 0;
1123
1124
0
    return 1;
1125
0
}
1126
1127
int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
1128
    CRYPTO_RWLOCK *lock)
1129
32
{
1130
32
#if defined(OSSL_USE_GCC_ATOMICS)
1131
32
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1132
32
        *ret = __atomic_or_fetch(val, op, __ATOMIC_ACQ_REL);
1133
32
        return 1;
1134
32
    }
1135
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1136
    /* This will work for all future Solaris versions. */
1137
    if (ret != NULL) {
1138
        *ret = atomic_or_64_nv(val, op);
1139
        return 1;
1140
    }
1141
#endif
1142
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1143
0
        return 0;
1144
0
    *val |= op;
1145
0
    *ret = *val;
1146
1147
0
    if (!CRYPTO_THREAD_unlock(lock))
1148
0
        return 0;
1149
1150
0
    return 1;
1151
0
}
1152
1153
int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
1154
535k
{
1155
535k
#if defined(OSSL_USE_GCC_ATOMICS)
1156
535k
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1157
535k
        __atomic_load(val, ret, __ATOMIC_ACQUIRE);
1158
535k
        return 1;
1159
535k
    }
1160
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1161
    /* This will work for all future Solaris versions. */
1162
    if (ret != NULL) {
1163
        *ret = atomic_or_64_nv(val, 0);
1164
        return 1;
1165
    }
1166
#endif
1167
0
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
1168
0
        return 0;
1169
0
    *ret = *val;
1170
0
    if (!CRYPTO_THREAD_unlock(lock))
1171
0
        return 0;
1172
1173
0
    return 1;
1174
0
}
1175
1176
int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock)
1177
6.41k
{
1178
6.41k
#if defined(OSSL_USE_GCC_ATOMICS)
1179
6.41k
    if (__atomic_is_lock_free(sizeof(*dst), dst)) {
1180
6.41k
        __atomic_store(dst, &val, __ATOMIC_RELEASE);
1181
6.41k
        return 1;
1182
6.41k
    }
1183
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1184
    /* This will work for all future Solaris versions. */
1185
    if (dst != NULL) {
1186
        atomic_swap_64(dst, val);
1187
        return 1;
1188
    }
1189
#endif
1190
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1191
0
        return 0;
1192
0
    *dst = val;
1193
0
    if (!CRYPTO_THREAD_unlock(lock))
1194
0
        return 0;
1195
1196
0
    return 1;
1197
0
}
1198
1199
int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock)
1200
0
{
1201
0
#if defined(OSSL_USE_GCC_ATOMICS)
1202
0
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1203
0
        __atomic_load(val, ret, __ATOMIC_ACQUIRE);
1204
0
        return 1;
1205
0
    }
1206
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1207
    /* This will work for all future Solaris versions. */
1208
    if (ret != NULL) {
1209
        *ret = (int)atomic_or_uint_nv((unsigned int *)val, 0);
1210
        return 1;
1211
    }
1212
#endif
1213
0
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
1214
0
        return 0;
1215
0
    *ret = *val;
1216
0
    if (!CRYPTO_THREAD_unlock(lock))
1217
0
        return 0;
1218
1219
0
    return 1;
1220
0
}
1221
1222
int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock)
1223
0
{
1224
0
#if defined(OSSL_USE_GCC_ATOMICS)
1225
0
    if (__atomic_is_lock_free(sizeof(*dst), dst)) {
1226
0
        __atomic_store(dst, &val, __ATOMIC_RELEASE);
1227
0
        return 1;
1228
0
    }
1229
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1230
    /* This will work for all future Solaris versions. */
1231
    if (dst != NULL) {
1232
        atomic_swap_uint((unsigned int)dst, (unsigned int)val);
1233
        return 1;
1234
    }
1235
#endif
1236
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1237
0
        return 0;
1238
0
    *dst = val;
1239
0
    if (!CRYPTO_THREAD_unlock(lock))
1240
0
        return 0;
1241
1242
0
    return 1;
1243
0
}
1244
1245
int CRYPTO_atomic_load_ptr(void **ptr, void **ret, CRYPTO_RWLOCK *lock)
1246
128
{
1247
128
#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
1248
128
    *ret = __atomic_load_n(ptr, __ATOMIC_RELAXED);
1249
128
    return 1;
1250
#else
1251
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
1252
        return 0;
1253
    *ret = *ptr;
1254
    if (!CRYPTO_THREAD_unlock(lock))
1255
        return 0;
1256
    return 1;
1257
#endif
1258
128
}
1259
1260
int CRYPTO_atomic_store_ptr(void **dst, void **val, CRYPTO_RWLOCK *lock)
1261
0
{
1262
0
#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
1263
0
    __atomic_store(dst, val, __ATOMIC_RELAXED);
1264
0
    return 1;
1265
#else
1266
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1267
        return 0;
1268
    *dst = *val;
1269
    if (!CRYPTO_THREAD_unlock(lock))
1270
        return 0;
1271
    return 1;
1272
#endif
1273
0
}
1274
1275
int CRYPTO_atomic_cmp_exch_ptr(void **ptr, void **expect, void *desire, CRYPTO_RWLOCK *lock)
1276
16
{
1277
16
#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
1278
16
    return __atomic_compare_exchange_n(ptr, expect, desire, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED) ? 1 : 0;
1279
#else
1280
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1281
        return 0;
1282
    if (*ptr == *expect)
1283
        *ptr = desire;
1284
    else
1285
        *expect = *ptr;
1286
    if (!CRYPTO_THREAD_unlock(lock))
1287
        return 0;
1288
    return 1;
1289
#endif
1290
16
}
1291
1292
#ifndef FIPS_MODULE
1293
int openssl_init_fork_handlers(void)
1294
0
{
1295
0
    return 1;
1296
0
}
1297
#endif /* FIPS_MODULE */
1298
1299
int openssl_get_fork_id(void)
1300
96
{
1301
96
    return getpid();
1302
96
}
1303
#endif