Coverage Report

Created: 2026-05-06 07:07

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
/*
521
 * Note: This call assumes its made under the protection of
522
 * ossl_rcu_write_lock
523
 */
524
int ossl_rcu_call(CRYPTO_RCU_LOCK *lock, rcu_cb_fn cb, void *data)
525
0
{
526
0
    struct rcu_cb_item *new = OPENSSL_zalloc(sizeof(*new));
527
528
0
    if (new == NULL)
529
0
        return 0;
530
531
0
    new->data = data;
532
0
    new->fn = cb;
533
534
0
    new->next = lock->cb_items;
535
0
    lock->cb_items = new;
536
537
0
    return 1;
538
0
}
539
540
void *ossl_rcu_uptr_deref(void **p)
541
421k
{
542
421k
    return ATOMIC_LOAD_N(pvoid, p, __ATOMIC_ACQUIRE);
543
421k
}
544
545
void ossl_rcu_assign_uptr(void **p, void **v)
546
6.41k
{
547
6.41k
    ATOMIC_STORE(pvoid, p, v, __ATOMIC_RELEASE);
548
6.41k
}
549
550
CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx)
551
16
{
552
16
    struct rcu_lock_st *new;
553
16
    pthread_mutex_t *mutexes[3] = { NULL };
554
16
    pthread_cond_t *conds[2] = { NULL };
555
16
    int i;
556
557
    /*
558
     * We need a minimum of 2 qp's
559
     */
560
16
    if (num_writers < 2)
561
16
        num_writers = 2;
562
563
16
    ctx = ossl_lib_ctx_get_concrete(ctx);
564
16
    if (ctx == NULL)
565
0
        return 0;
566
567
16
    new = OPENSSL_zalloc(sizeof(*new));
568
16
    if (new == NULL)
569
0
        return NULL;
570
571
16
    new->ctx = ctx;
572
16
    i = 0;
573
16
    mutexes[i] = pthread_mutex_init(&new->write_lock, NULL) == 0 ? &new->write_lock : NULL;
574
16
    if (mutexes[i++] == NULL)
575
0
        goto err;
576
16
    mutexes[i] = pthread_mutex_init(&new->prior_lock, NULL) == 0 ? &new->prior_lock : NULL;
577
16
    if (mutexes[i++] == NULL)
578
0
        goto err;
579
16
    mutexes[i] = pthread_mutex_init(&new->alloc_lock, NULL) == 0 ? &new->alloc_lock : NULL;
580
16
    if (mutexes[i++] == NULL)
581
0
        goto err;
582
16
    conds[i - 3] = pthread_cond_init(&new->prior_signal, NULL) == 0 ? &new->prior_signal : NULL;
583
16
    if (conds[i - 3] == NULL)
584
0
        goto err;
585
16
    i++;
586
16
    conds[i - 3] = pthread_cond_init(&new->alloc_signal, NULL) == 0 ? &new->alloc_signal : NULL;
587
16
    if (conds[i - 3] == NULL)
588
0
        goto err;
589
16
    i++;
590
16
    new->qp_group = allocate_new_qp_group(new, num_writers);
591
16
    if (new->qp_group == NULL)
592
0
        goto err;
593
594
16
    return new;
595
596
0
err:
597
0
    for (i = 0; i < 3; i++)
598
0
        if (mutexes[i] != NULL)
599
0
            pthread_mutex_destroy(mutexes[i]);
600
0
    for (i = 0; i < 2; i++)
601
0
        if (conds[i] != NULL)
602
0
            pthread_cond_destroy(conds[i]);
603
0
    OPENSSL_free(new->qp_group);
604
0
    OPENSSL_free(new);
605
0
    return NULL;
606
16
}
607
608
void ossl_rcu_lock_free(CRYPTO_RCU_LOCK *lock)
609
0
{
610
0
    struct rcu_lock_st *rlock = (struct rcu_lock_st *)lock;
611
612
0
    if (lock == NULL)
613
0
        return;
614
615
    /* make sure we're synchronized */
616
0
    ossl_synchronize_rcu(rlock);
617
618
0
    OPENSSL_free(rlock->qp_group);
619
    /*
620
     * Some targets (BSD) allocate heap when initializing
621
     * a mutex or condition, to prevent leaks, those need
622
     * to be destroyed here
623
     */
624
0
    pthread_mutex_destroy(&rlock->write_lock);
625
0
    pthread_mutex_destroy(&rlock->prior_lock);
626
0
    pthread_mutex_destroy(&rlock->alloc_lock);
627
0
    pthread_cond_destroy(&rlock->prior_signal);
628
0
    pthread_cond_destroy(&rlock->alloc_signal);
629
630
    /* There should only be a single qp left now */
631
0
    OPENSSL_free(rlock);
632
0
}
633
634
#ifdef REPORT_RWLOCK_CONTENTION
635
/*
636
 * Normally we would use a BIO here to do this, but we create locks during
637
 * library initialization, and creating a bio too early, creates a recursive set
638
 * of stack calls that leads us to call CRYPTO_thread_run_once while currently
639
 * executing the init routine for various run_once functions, which leads to
640
 * deadlock.  Avoid that by just using a FILE pointer.  Also note that we
641
 * directly use a pthread_mutex_t to protect access from multiple threads
642
 * to the contention log file.  We do this because we want to avoid use
643
 * of the CRYPTO_THREAD api so as to prevent recursive blocking reports.
644
 */
645
static CRYPTO_ONCE init_contention_data_flag = CRYPTO_ONCE_STATIC_INIT;
646
pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
647
CRYPTO_THREAD_LOCAL thread_contention_data;
648
649
struct stack_info {
650
    unsigned int nptrs;
651
    int write;
652
    OSSL_TIME start;
653
    OSSL_TIME duration;
654
    char **strings;
655
};
656
657
#define STACKS_COUNT 32
658
#define BT_BUF_SIZE 1024
659
struct stack_traces {
660
    int fd;
661
    int lock_depth;
662
    size_t idx;
663
    struct stack_info stacks[STACKS_COUNT];
664
};
665
666
/* The glibc gettid() definition presents only since 2.30. */
667
static ossl_inline pid_t get_tid(void)
668
{
669
#ifdef OPENSSL_SYS_MACOSX
670
    /*
671
     * MACOS has the gettid call, but it does something completely different
672
     * here than on other unixes.  Specifically it returns the uid of the calling thread
673
     * (if set), or -1.  We need to use a MACOS specific call to get the thread id here
674
     */
675
    uint64_t tid;
676
677
    pthread_threadid_np(NULL, &tid);
678
    return (pid_t)tid;
679
#else
680
    return syscall(SYS_gettid);
681
#endif
682
}
683
684
#ifdef FIPS_MODULE
685
#define FIPS_SFX "-fips"
686
#else
687
#define FIPS_SFX ""
688
#endif
689
static void *init_contention_data(void)
690
{
691
    struct stack_traces *traces;
692
    char fname_fmt[] = "lock-contention-log" FIPS_SFX ".%d.txt";
693
    char fname[sizeof(fname_fmt) + sizeof(int) * 3];
694
695
    traces = OPENSSL_zalloc(sizeof(struct stack_traces));
696
697
    snprintf(fname, sizeof(fname), fname_fmt, get_tid());
698
699
    traces->fd = open(fname, O_WRONLY | O_APPEND | O_CLOEXEC | O_CREAT, 0600);
700
701
    return traces;
702
}
703
704
static void destroy_contention_data(void *data)
705
{
706
    struct stack_traces *st = data;
707
708
    close(st->fd);
709
    OPENSSL_free(data);
710
}
711
712
static void init_contention_data_once(void)
713
{
714
    /*
715
     * Create a thread local key here to store our list of stack traces
716
     * to be printed when we unlock the lock we are holding
717
     */
718
    CRYPTO_THREAD_init_local(&thread_contention_data, destroy_contention_data);
719
    return;
720
}
721
722
static struct stack_traces *get_stack_traces(bool init)
723
{
724
    struct stack_traces *traces = CRYPTO_THREAD_get_local(&thread_contention_data);
725
726
    if (!traces && init) {
727
        traces = init_contention_data();
728
        CRYPTO_THREAD_set_local(&thread_contention_data, traces);
729
    }
730
731
    return traces;
732
}
733
734
static void print_stack_traces(struct stack_traces *traces)
735
{
736
    unsigned int j;
737
    struct iovec *iov;
738
    int iovcnt;
739
740
    while (traces != NULL && traces->idx >= 1) {
741
        traces->idx--;
742
        dprintf(traces->fd,
743
            "lock blocked on %s for %zu usec at time %zu tid %d\n",
744
            traces->stacks[traces->idx].write == 1 ? "WRITE" : "READ",
745
            ossl_time2us(traces->stacks[traces->idx].duration),
746
            ossl_time2us(traces->stacks[traces->idx].start),
747
            get_tid());
748
        if (traces->stacks[traces->idx].strings != NULL) {
749
            static const char lf = '\n';
750
751
            iovcnt = traces->stacks[traces->idx].nptrs * 2 + 1;
752
            iov = alloca(iovcnt * sizeof(*iov));
753
            for (j = 0; j < traces->stacks[traces->idx].nptrs; j++) {
754
                iov[2 * j].iov_base = traces->stacks[traces->idx].strings[j];
755
                iov[2 * j].iov_len = strlen(traces->stacks[traces->idx].strings[j]);
756
                iov[2 * j + 1].iov_base = (char *)&lf;
757
                iov[2 * j + 1].iov_len = 1;
758
            }
759
            iov[traces->stacks[traces->idx].nptrs * 2].iov_base = (char *)&lf;
760
            iov[traces->stacks[traces->idx].nptrs * 2].iov_len = 1;
761
        } else {
762
            static const char no_bt[] = "No stack trace available\n\n";
763
764
            iovcnt = 1;
765
            iov = alloca(iovcnt * sizeof(*iov));
766
            iov[0].iov_base = (char *)no_bt;
767
            iov[0].iov_len = sizeof(no_bt) - 1;
768
        }
769
        writev(traces->fd, iov, iovcnt);
770
        free(traces->stacks[traces->idx].strings);
771
    }
772
}
773
774
static ossl_inline void ossl_init_rwlock_contention_data(void)
775
{
776
    CRYPTO_THREAD_run_once(&init_contention_data_flag, init_contention_data_once);
777
}
778
779
static int record_lock_contention(pthread_rwlock_t *lock,
780
    struct stack_traces *traces, bool write)
781
{
782
    void *buffer[BT_BUF_SIZE];
783
    OSSL_TIME start, end;
784
    int ret;
785
786
    start = ossl_time_now();
787
    ret = (write ? pthread_rwlock_wrlock : pthread_rwlock_rdlock)(lock);
788
    if (ret)
789
        return ret;
790
    end = ossl_time_now();
791
    traces->stacks[traces->idx].nptrs = backtrace(buffer, BT_BUF_SIZE);
792
    traces->stacks[traces->idx].strings = backtrace_symbols(buffer,
793
        traces->stacks[traces->idx].nptrs);
794
    traces->stacks[traces->idx].duration = ossl_time_subtract(end, start);
795
    traces->stacks[traces->idx].start = start;
796
    traces->stacks[traces->idx].write = write;
797
    traces->idx++;
798
    if (traces->idx >= STACKS_COUNT) {
799
        fprintf(stderr, "STACK RECORD OVERFLOW!\n");
800
        print_stack_traces(traces);
801
    }
802
803
    return 0;
804
}
805
806
static ossl_inline int ossl_rwlock_rdlock(pthread_rwlock_t *lock)
807
{
808
    struct stack_traces *traces = get_stack_traces(true);
809
810
    if (ossl_unlikely(traces == NULL))
811
        return ENOMEM;
812
813
    traces->lock_depth++;
814
    if (pthread_rwlock_tryrdlock(lock)) {
815
        int ret = record_lock_contention(lock, traces, false);
816
817
        if (ret)
818
            traces->lock_depth--;
819
820
        return ret;
821
    }
822
823
    return 0;
824
}
825
826
static ossl_inline int ossl_rwlock_wrlock(pthread_rwlock_t *lock)
827
{
828
    struct stack_traces *traces = get_stack_traces(true);
829
830
    if (ossl_unlikely(traces == NULL))
831
        return ENOMEM;
832
833
    traces->lock_depth++;
834
    if (pthread_rwlock_trywrlock(lock)) {
835
        int ret = record_lock_contention(lock, traces, true);
836
837
        if (ret)
838
            traces->lock_depth--;
839
840
        return ret;
841
    }
842
843
    return 0;
844
}
845
846
static ossl_inline int ossl_rwlock_unlock(pthread_rwlock_t *lock)
847
{
848
    int ret;
849
850
    ret = pthread_rwlock_unlock(lock);
851
    if (ret)
852
        return ret;
853
854
    {
855
        struct stack_traces *traces = get_stack_traces(false);
856
857
        if (traces != NULL) {
858
            traces->lock_depth--;
859
            assert(traces->lock_depth >= 0);
860
            if (traces->lock_depth == 0)
861
                print_stack_traces(traces);
862
        }
863
    }
864
865
    return 0;
866
}
867
868
#else /* !REPORT_RWLOCK_CONTENTION */
869
870
#if defined(USE_RWLOCK)
871
static ossl_inline void ossl_init_rwlock_contention_data(void)
872
51.4k
{
873
51.4k
}
874
875
static ossl_inline int ossl_rwlock_rdlock(pthread_rwlock_t *rwlock)
876
325k
{
877
325k
    return pthread_rwlock_rdlock(rwlock);
878
325k
}
879
880
static ossl_inline int ossl_rwlock_wrlock(pthread_rwlock_t *rwlock)
881
24.7k
{
882
24.7k
    return pthread_rwlock_wrlock(rwlock);
883
24.7k
}
884
885
static ossl_inline int ossl_rwlock_unlock(pthread_rwlock_t *rwlock)
886
349k
{
887
349k
    return pthread_rwlock_unlock(rwlock);
888
349k
}
889
#endif /* USE_RWLOCK */
890
#endif /* REPORT_RWLOCK_CONTENTION */
891
892
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
893
51.4k
{
894
51.4k
#ifdef USE_RWLOCK
895
51.4k
    CRYPTO_RWLOCK *lock;
896
897
51.4k
    ossl_init_rwlock_contention_data();
898
899
51.4k
    if ((lock = OPENSSL_zalloc(sizeof(pthread_rwlock_t))) == NULL)
900
        /* Don't set error, to avoid recursion blowup. */
901
0
        return NULL;
902
903
51.4k
    if (pthread_rwlock_init(lock, NULL) != 0) {
904
0
        OPENSSL_free(lock);
905
0
        return NULL;
906
0
    }
907
#else
908
    pthread_mutexattr_t attr;
909
    CRYPTO_RWLOCK *lock;
910
911
    if ((lock = OPENSSL_zalloc(sizeof(pthread_mutex_t))) == NULL)
912
        /* Don't set error, to avoid recursion blowup. */
913
        return NULL;
914
915
    /*
916
     * We don't use recursive mutexes, but try to catch errors if we do.
917
     */
918
    pthread_mutexattr_init(&attr);
919
#if !defined(__TANDEM) && !defined(_SPT_MODEL_)
920
#if !defined(NDEBUG) && !defined(OPENSSL_NO_MUTEX_ERRORCHECK)
921
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
922
#endif
923
#else
924
    /* The SPT Thread Library does not define MUTEX attributes. */
925
#endif
926
927
    if (pthread_mutex_init(lock, &attr) != 0) {
928
        pthread_mutexattr_destroy(&attr);
929
        OPENSSL_free(lock);
930
        return NULL;
931
    }
932
933
    pthread_mutexattr_destroy(&attr);
934
#endif
935
936
51.4k
    return lock;
937
51.4k
}
938
939
__owur int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
940
325k
{
941
325k
#ifdef USE_RWLOCK
942
325k
    if (!ossl_assert(ossl_rwlock_rdlock(lock) == 0))
943
0
        return 0;
944
#else
945
    if (pthread_mutex_lock(lock) != 0) {
946
        assert(errno != EDEADLK && errno != EBUSY);
947
        return 0;
948
    }
949
#endif
950
951
325k
    return 1;
952
325k
}
953
954
__owur int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
955
24.7k
{
956
24.7k
#ifdef USE_RWLOCK
957
24.7k
    if (!ossl_assert(ossl_rwlock_wrlock(lock) == 0))
958
0
        return 0;
959
#else
960
    if (pthread_mutex_lock(lock) != 0) {
961
        assert(errno != EDEADLK && errno != EBUSY);
962
        return 0;
963
    }
964
#endif
965
966
24.7k
    return 1;
967
24.7k
}
968
969
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
970
349k
{
971
349k
#ifdef USE_RWLOCK
972
349k
    if (ossl_rwlock_unlock(lock) != 0)
973
0
        return 0;
974
#else
975
    if (pthread_mutex_unlock(lock) != 0) {
976
        assert(errno != EPERM);
977
        return 0;
978
    }
979
#endif
980
981
349k
    return 1;
982
349k
}
983
984
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
985
50.8k
{
986
50.8k
    if (lock == NULL)
987
0
        return;
988
989
50.8k
#ifdef USE_RWLOCK
990
50.8k
    pthread_rwlock_destroy(lock);
991
#else
992
    pthread_mutex_destroy(lock);
993
#endif
994
50.8k
    OPENSSL_free(lock);
995
996
50.8k
    return;
997
50.8k
}
998
999
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
1000
1.20M
{
1001
1.20M
    if (ossl_unlikely(pthread_once(once, init) != 0))
1002
0
        return 0;
1003
1004
1.20M
    return 1;
1005
1.20M
}
1006
1007
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
1008
64
{
1009
64
    if (pthread_key_create(key, cleanup) != 0)
1010
0
        return 0;
1011
1012
64
    return 1;
1013
64
}
1014
1015
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
1016
546k
{
1017
546k
    return pthread_getspecific(*key);
1018
546k
}
1019
1020
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
1021
48
{
1022
48
    if (pthread_setspecific(*key, val) != 0)
1023
0
        return 0;
1024
1025
48
    return 1;
1026
48
}
1027
1028
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
1029
0
{
1030
0
    if (pthread_key_delete(*key) != 0)
1031
0
        return 0;
1032
1033
0
    return 1;
1034
0
}
1035
1036
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
1037
0
{
1038
0
    return pthread_self();
1039
0
}
1040
1041
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
1042
0
{
1043
0
    return pthread_equal(a, b);
1044
0
}
1045
1046
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
1047
122
{
1048
122
#if defined(OSSL_USE_GCC_ATOMICS)
1049
122
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1050
122
        *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL);
1051
122
        return 1;
1052
122
    }
1053
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1054
    /* This will work for all future Solaris versions. */
1055
    if (ret != NULL) {
1056
        *ret = atomic_add_int_nv((volatile unsigned int *)val, amount);
1057
        return 1;
1058
    }
1059
#endif
1060
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1061
0
        return 0;
1062
1063
0
    *val += amount;
1064
0
    *ret = *val;
1065
1066
0
    if (!CRYPTO_THREAD_unlock(lock))
1067
0
        return 0;
1068
1069
0
    return 1;
1070
0
}
1071
1072
int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret,
1073
    CRYPTO_RWLOCK *lock)
1074
0
{
1075
0
#if defined(OSSL_USE_GCC_ATOMICS)
1076
0
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1077
0
        *ret = __atomic_add_fetch(val, op, __ATOMIC_ACQ_REL);
1078
0
        return 1;
1079
0
    }
1080
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1081
    /* This will work for all future Solaris versions. */
1082
    if (ret != NULL) {
1083
        *ret = atomic_add_64_nv(val, op);
1084
        return 1;
1085
    }
1086
#endif
1087
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1088
0
        return 0;
1089
0
    *val += op;
1090
0
    *ret = *val;
1091
1092
0
    if (!CRYPTO_THREAD_unlock(lock))
1093
0
        return 0;
1094
1095
0
    return 1;
1096
0
}
1097
1098
int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret,
1099
    CRYPTO_RWLOCK *lock)
1100
0
{
1101
0
#if defined(OSSL_USE_GCC_ATOMICS)
1102
0
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1103
0
        *ret = __atomic_and_fetch(val, op, __ATOMIC_ACQ_REL);
1104
0
        return 1;
1105
0
    }
1106
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1107
    /* This will work for all future Solaris versions. */
1108
    if (ret != NULL) {
1109
        *ret = atomic_and_64_nv(val, op);
1110
        return 1;
1111
    }
1112
#endif
1113
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1114
0
        return 0;
1115
0
    *val &= op;
1116
0
    *ret = *val;
1117
1118
0
    if (!CRYPTO_THREAD_unlock(lock))
1119
0
        return 0;
1120
1121
0
    return 1;
1122
0
}
1123
1124
int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
1125
    CRYPTO_RWLOCK *lock)
1126
32
{
1127
32
#if defined(OSSL_USE_GCC_ATOMICS)
1128
32
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1129
32
        *ret = __atomic_or_fetch(val, op, __ATOMIC_ACQ_REL);
1130
32
        return 1;
1131
32
    }
1132
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1133
    /* This will work for all future Solaris versions. */
1134
    if (ret != NULL) {
1135
        *ret = atomic_or_64_nv(val, op);
1136
        return 1;
1137
    }
1138
#endif
1139
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1140
0
        return 0;
1141
0
    *val |= op;
1142
0
    *ret = *val;
1143
1144
0
    if (!CRYPTO_THREAD_unlock(lock))
1145
0
        return 0;
1146
1147
0
    return 1;
1148
0
}
1149
1150
int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
1151
533k
{
1152
533k
#if defined(OSSL_USE_GCC_ATOMICS)
1153
533k
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1154
533k
        __atomic_load(val, ret, __ATOMIC_ACQUIRE);
1155
533k
        return 1;
1156
533k
    }
1157
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1158
    /* This will work for all future Solaris versions. */
1159
    if (ret != NULL) {
1160
        *ret = atomic_or_64_nv(val, 0);
1161
        return 1;
1162
    }
1163
#endif
1164
0
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
1165
0
        return 0;
1166
0
    *ret = *val;
1167
0
    if (!CRYPTO_THREAD_unlock(lock))
1168
0
        return 0;
1169
1170
0
    return 1;
1171
0
}
1172
1173
int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock)
1174
6.41k
{
1175
6.41k
#if defined(OSSL_USE_GCC_ATOMICS)
1176
6.41k
    if (__atomic_is_lock_free(sizeof(*dst), dst)) {
1177
6.41k
        __atomic_store(dst, &val, __ATOMIC_RELEASE);
1178
6.41k
        return 1;
1179
6.41k
    }
1180
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1181
    /* This will work for all future Solaris versions. */
1182
    if (dst != NULL) {
1183
        atomic_swap_64(dst, val);
1184
        return 1;
1185
    }
1186
#endif
1187
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1188
0
        return 0;
1189
0
    *dst = val;
1190
0
    if (!CRYPTO_THREAD_unlock(lock))
1191
0
        return 0;
1192
1193
0
    return 1;
1194
0
}
1195
1196
int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock)
1197
0
{
1198
0
#if defined(OSSL_USE_GCC_ATOMICS)
1199
0
    if (__atomic_is_lock_free(sizeof(*val), val)) {
1200
0
        __atomic_load(val, ret, __ATOMIC_ACQUIRE);
1201
0
        return 1;
1202
0
    }
1203
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1204
    /* This will work for all future Solaris versions. */
1205
    if (ret != NULL) {
1206
        *ret = (int)atomic_or_uint_nv((unsigned int *)val, 0);
1207
        return 1;
1208
    }
1209
#endif
1210
0
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
1211
0
        return 0;
1212
0
    *ret = *val;
1213
0
    if (!CRYPTO_THREAD_unlock(lock))
1214
0
        return 0;
1215
1216
0
    return 1;
1217
0
}
1218
1219
int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock)
1220
0
{
1221
0
#if defined(OSSL_USE_GCC_ATOMICS)
1222
0
    if (__atomic_is_lock_free(sizeof(*dst), dst)) {
1223
0
        __atomic_store(dst, &val, __ATOMIC_RELEASE);
1224
0
        return 1;
1225
0
    }
1226
#elif defined(OSSL_USE_SOLARIS_ATOMICS)
1227
    /* This will work for all future Solaris versions. */
1228
    if (dst != NULL) {
1229
        atomic_swap_uint((unsigned int)dst, (unsigned int)val);
1230
        return 1;
1231
    }
1232
#endif
1233
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1234
0
        return 0;
1235
0
    *dst = val;
1236
0
    if (!CRYPTO_THREAD_unlock(lock))
1237
0
        return 0;
1238
1239
0
    return 1;
1240
0
}
1241
1242
int CRYPTO_atomic_load_ptr(void **ptr, void **ret, CRYPTO_RWLOCK *lock)
1243
128
{
1244
128
#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
1245
128
    *ret = __atomic_load_n(ptr, __ATOMIC_RELAXED);
1246
128
    return 1;
1247
#else
1248
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
1249
        return 0;
1250
    *ret = *ptr;
1251
    if (!CRYPTO_THREAD_unlock(lock))
1252
        return 0;
1253
    return 1;
1254
#endif
1255
128
}
1256
1257
int CRYPTO_atomic_store_ptr(void **dst, void **val, CRYPTO_RWLOCK *lock)
1258
0
{
1259
0
#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
1260
0
    __atomic_store(dst, val, __ATOMIC_RELAXED);
1261
0
    return 1;
1262
#else
1263
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1264
        return 0;
1265
    *dst = *val;
1266
    if (!CRYPTO_THREAD_unlock(lock))
1267
        return 0;
1268
    return 1;
1269
#endif
1270
0
}
1271
1272
int CRYPTO_atomic_cmp_exch_ptr(void **ptr, void **expect, void *desire, CRYPTO_RWLOCK *lock)
1273
16
{
1274
16
#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
1275
16
    return __atomic_compare_exchange_n(ptr, expect, desire, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED) ? 1 : 0;
1276
#else
1277
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
1278
        return 0;
1279
    if (*ptr == *expect)
1280
        *ptr = desire;
1281
    else
1282
        *expect = *ptr;
1283
    if (!CRYPTO_THREAD_unlock(lock))
1284
        return 0;
1285
    return 1;
1286
#endif
1287
16
}
1288
1289
#ifndef FIPS_MODULE
1290
int openssl_init_fork_handlers(void)
1291
0
{
1292
0
    return 1;
1293
0
}
1294
#endif /* FIPS_MODULE */
1295
1296
int openssl_get_fork_id(void)
1297
96
{
1298
96
    return getpid();
1299
96
}
1300
#endif