refcount_c11.c revision 53b272a2813a0b11f107d77100ff8805ada8fbd2
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. */ 29static_assert(alignof(CRYPTO_refcount_t) == alignof(_Atomic CRYPTO_refcount_t), 30 "_Atomic alters the needed alignment of a reference count"); 31static_assert(sizeof(CRYPTO_refcount_t) == sizeof(_Atomic CRYPTO_refcount_t), 32 "_Atomic alters the size of a reference count"); 33 34static_assert((CRYPTO_refcount_t)-1 == CRYPTO_REFCOUNT_MAX, 35 "CRYPTO_REFCOUNT_MAX is incorrect"); 36 37void 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 49int 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