1 | /* Copyright (c) 2015, Google Inc. |
2 | * |
3 | * Permission to use, copy, modify, and/or distribute this software for any |
4 | * purpose with or without fee is hereby granted, provided that the above |
5 | * copyright notice and this permission notice appear in all copies. |
6 | * |
7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
14 | |
15 | #include "internal.h" |
16 | |
17 | |
18 | #if defined(OPENSSL_C11_ATOMIC) |
19 | |
20 | #include <assert.h> |
21 | #include <stdalign.h> |
22 | #include <stdatomic.h> |
23 | #include <stdlib.h> |
24 | |
25 | #include <openssl/type_check.h> |
26 | |
27 | |
28 | // See comment above the typedef of CRYPTO_refcount_t about these tests. |
29 | static_assert(alignof(CRYPTO_refcount_t) == alignof(_Atomic CRYPTO_refcount_t), |
30 | "_Atomic alters the needed alignment of a reference count" ); |
31 | static_assert(sizeof(CRYPTO_refcount_t) == sizeof(_Atomic CRYPTO_refcount_t), |
32 | "_Atomic alters the size of a reference count" ); |
33 | |
34 | static_assert((CRYPTO_refcount_t)-1 == CRYPTO_REFCOUNT_MAX, |
35 | "CRYPTO_REFCOUNT_MAX is incorrect" ); |
36 | |
37 | void CRYPTO_refcount_inc(CRYPTO_refcount_t *in_count) { |
38 | _Atomic CRYPTO_refcount_t *count = (_Atomic CRYPTO_refcount_t *) in_count; |
39 | uint32_t expected = atomic_load(count); |
40 | |
41 | while (expected != CRYPTO_REFCOUNT_MAX) { |
42 | uint32_t new_value = expected + 1; |
43 | if (atomic_compare_exchange_weak(count, &expected, new_value)) { |
44 | break; |
45 | } |
46 | } |
47 | } |
48 | |
49 | int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *in_count) { |
50 | _Atomic CRYPTO_refcount_t *count = (_Atomic CRYPTO_refcount_t *)in_count; |
51 | uint32_t expected = atomic_load(count); |
52 | |
53 | for (;;) { |
54 | if (expected == 0) { |
55 | abort(); |
56 | } else if (expected == CRYPTO_REFCOUNT_MAX) { |
57 | return 0; |
58 | } else { |
59 | const uint32_t new_value = expected - 1; |
60 | if (atomic_compare_exchange_weak(count, &expected, new_value)) { |
61 | return new_value == 0; |
62 | } |
63 | } |
64 | } |
65 | } |
66 | |
67 | #endif // OPENSSL_C11_ATOMIC |
68 | |