xref: /freebsd/crypto/openssl/include/internal/refcount.h (revision e71b70530d95c4f34d8bdbd78d1242df1ba4a945)
1*e71b7053SJung-uk Kim /*
2*e71b7053SJung-uk Kim  * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
3*e71b7053SJung-uk Kim  *
4*e71b7053SJung-uk Kim  * Licensed under the OpenSSL license (the "License").  You may not use
5*e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6*e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7*e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
8*e71b7053SJung-uk Kim  */
9*e71b7053SJung-uk Kim #ifndef HEADER_INTERNAL_REFCOUNT_H
10*e71b7053SJung-uk Kim # define HEADER_INTERNAL_REFCOUNT_H
11*e71b7053SJung-uk Kim 
12*e71b7053SJung-uk Kim /* Used to checking reference counts, most while doing perl5 stuff :-) */
13*e71b7053SJung-uk Kim # if defined(OPENSSL_NO_STDIO)
14*e71b7053SJung-uk Kim #  if defined(REF_PRINT)
15*e71b7053SJung-uk Kim #   error "REF_PRINT requires stdio"
16*e71b7053SJung-uk Kim #  endif
17*e71b7053SJung-uk Kim # endif
18*e71b7053SJung-uk Kim 
19*e71b7053SJung-uk Kim # if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
20*e71b7053SJung-uk Kim      && !defined(__STDC_NO_ATOMICS__)
21*e71b7053SJung-uk Kim #  include <stdatomic.h>
22*e71b7053SJung-uk Kim #  define HAVE_C11_ATOMICS
23*e71b7053SJung-uk Kim # endif
24*e71b7053SJung-uk Kim 
25*e71b7053SJung-uk Kim # if defined(HAVE_C11_ATOMICS) && defined(ATOMIC_INT_LOCK_FREE) \
26*e71b7053SJung-uk Kim      && ATOMIC_INT_LOCK_FREE > 0
27*e71b7053SJung-uk Kim 
28*e71b7053SJung-uk Kim #  define HAVE_ATOMICS 1
29*e71b7053SJung-uk Kim 
30*e71b7053SJung-uk Kim typedef _Atomic int CRYPTO_REF_COUNT;
31*e71b7053SJung-uk Kim 
32*e71b7053SJung-uk Kim static inline int CRYPTO_UP_REF(_Atomic int *val, int *ret, void *lock)
33*e71b7053SJung-uk Kim {
34*e71b7053SJung-uk Kim     *ret = atomic_fetch_add_explicit(val, 1, memory_order_relaxed) + 1;
35*e71b7053SJung-uk Kim     return 1;
36*e71b7053SJung-uk Kim }
37*e71b7053SJung-uk Kim 
38*e71b7053SJung-uk Kim /*
39*e71b7053SJung-uk Kim  * Changes to shared structure other than reference counter have to be
40*e71b7053SJung-uk Kim  * serialized. And any kind of serialization implies a release fence. This
41*e71b7053SJung-uk Kim  * means that by the time reference counter is decremented all other
42*e71b7053SJung-uk Kim  * changes are visible on all processors. Hence decrement itself can be
43*e71b7053SJung-uk Kim  * relaxed. In case it hits zero, object will be destructed. Since it's
44*e71b7053SJung-uk Kim  * last use of the object, destructor programmer might reason that access
45*e71b7053SJung-uk Kim  * to mutable members doesn't have to be serialized anymore, which would
46*e71b7053SJung-uk Kim  * otherwise imply an acquire fence. Hence conditional acquire fence...
47*e71b7053SJung-uk Kim  */
48*e71b7053SJung-uk Kim static inline int CRYPTO_DOWN_REF(_Atomic int *val, int *ret, void *lock)
49*e71b7053SJung-uk Kim {
50*e71b7053SJung-uk Kim     *ret = atomic_fetch_sub_explicit(val, 1, memory_order_relaxed) - 1;
51*e71b7053SJung-uk Kim     if (*ret == 0)
52*e71b7053SJung-uk Kim         atomic_thread_fence(memory_order_acquire);
53*e71b7053SJung-uk Kim     return 1;
54*e71b7053SJung-uk Kim }
55*e71b7053SJung-uk Kim 
56*e71b7053SJung-uk Kim # elif defined(__GNUC__) && defined(__ATOMIC_RELAXED) && __GCC_ATOMIC_INT_LOCK_FREE > 0
57*e71b7053SJung-uk Kim 
58*e71b7053SJung-uk Kim #  define HAVE_ATOMICS 1
59*e71b7053SJung-uk Kim 
60*e71b7053SJung-uk Kim typedef int CRYPTO_REF_COUNT;
61*e71b7053SJung-uk Kim 
62*e71b7053SJung-uk Kim static __inline__ int CRYPTO_UP_REF(int *val, int *ret, void *lock)
63*e71b7053SJung-uk Kim {
64*e71b7053SJung-uk Kim     *ret = __atomic_fetch_add(val, 1, __ATOMIC_RELAXED) + 1;
65*e71b7053SJung-uk Kim     return 1;
66*e71b7053SJung-uk Kim }
67*e71b7053SJung-uk Kim 
68*e71b7053SJung-uk Kim static __inline__ int CRYPTO_DOWN_REF(int *val, int *ret, void *lock)
69*e71b7053SJung-uk Kim {
70*e71b7053SJung-uk Kim     *ret = __atomic_fetch_sub(val, 1, __ATOMIC_RELAXED) - 1;
71*e71b7053SJung-uk Kim     if (*ret == 0)
72*e71b7053SJung-uk Kim         __atomic_thread_fence(__ATOMIC_ACQUIRE);
73*e71b7053SJung-uk Kim     return 1;
74*e71b7053SJung-uk Kim }
75*e71b7053SJung-uk Kim 
76*e71b7053SJung-uk Kim # elif defined(_MSC_VER) && _MSC_VER>=1200
77*e71b7053SJung-uk Kim 
78*e71b7053SJung-uk Kim #  define HAVE_ATOMICS 1
79*e71b7053SJung-uk Kim 
80*e71b7053SJung-uk Kim typedef volatile int CRYPTO_REF_COUNT;
81*e71b7053SJung-uk Kim 
82*e71b7053SJung-uk Kim #  if (defined(_M_ARM) && _M_ARM>=7) || defined(_M_ARM64)
83*e71b7053SJung-uk Kim #   include <intrin.h>
84*e71b7053SJung-uk Kim #   if defined(_M_ARM64) && !defined(_ARM_BARRIER_ISH)
85*e71b7053SJung-uk Kim #    define _ARM_BARRIER_ISH _ARM64_BARRIER_ISH
86*e71b7053SJung-uk Kim #   endif
87*e71b7053SJung-uk Kim 
88*e71b7053SJung-uk Kim static __inline int CRYPTO_UP_REF(volatile int *val, int *ret, void *lock)
89*e71b7053SJung-uk Kim {
90*e71b7053SJung-uk Kim     *ret = _InterlockedExchangeAdd_nf(val, 1) + 1;
91*e71b7053SJung-uk Kim     return 1;
92*e71b7053SJung-uk Kim }
93*e71b7053SJung-uk Kim 
94*e71b7053SJung-uk Kim static __inline int CRYPTO_DOWN_REF(volatile int *val, int *ret, void *lock)
95*e71b7053SJung-uk Kim {
96*e71b7053SJung-uk Kim     *ret = _InterlockedExchangeAdd_nf(val, -1) - 1;
97*e71b7053SJung-uk Kim     if (*ret == 0)
98*e71b7053SJung-uk Kim         __dmb(_ARM_BARRIER_ISH);
99*e71b7053SJung-uk Kim     return 1;
100*e71b7053SJung-uk Kim }
101*e71b7053SJung-uk Kim #  else
102*e71b7053SJung-uk Kim #   pragma intrinsic(_InterlockedExchangeAdd)
103*e71b7053SJung-uk Kim 
104*e71b7053SJung-uk Kim static __inline int CRYPTO_UP_REF(volatile int *val, int *ret, void *lock)
105*e71b7053SJung-uk Kim {
106*e71b7053SJung-uk Kim     *ret = _InterlockedExchangeAdd(val, 1) + 1;
107*e71b7053SJung-uk Kim     return 1;
108*e71b7053SJung-uk Kim }
109*e71b7053SJung-uk Kim 
110*e71b7053SJung-uk Kim static __inline int CRYPTO_DOWN_REF(volatile int *val, int *ret, void *lock)
111*e71b7053SJung-uk Kim {
112*e71b7053SJung-uk Kim     *ret = _InterlockedExchangeAdd(val, -1) - 1;
113*e71b7053SJung-uk Kim     return 1;
114*e71b7053SJung-uk Kim }
115*e71b7053SJung-uk Kim #  endif
116*e71b7053SJung-uk Kim 
117*e71b7053SJung-uk Kim # else
118*e71b7053SJung-uk Kim 
119*e71b7053SJung-uk Kim typedef int CRYPTO_REF_COUNT;
120*e71b7053SJung-uk Kim 
121*e71b7053SJung-uk Kim # define CRYPTO_UP_REF(val, ret, lock) CRYPTO_atomic_add(val, 1, ret, lock)
122*e71b7053SJung-uk Kim # define CRYPTO_DOWN_REF(val, ret, lock) CRYPTO_atomic_add(val, -1, ret, lock)
123*e71b7053SJung-uk Kim 
124*e71b7053SJung-uk Kim # endif
125*e71b7053SJung-uk Kim 
126*e71b7053SJung-uk Kim # if !defined(NDEBUG) && !defined(OPENSSL_NO_STDIO)
127*e71b7053SJung-uk Kim #  define REF_ASSERT_ISNT(test) \
128*e71b7053SJung-uk Kim     (void)((test) ? (OPENSSL_die("refcount error", __FILE__, __LINE__), 1) : 0)
129*e71b7053SJung-uk Kim # else
130*e71b7053SJung-uk Kim #  define REF_ASSERT_ISNT(i)
131*e71b7053SJung-uk Kim # endif
132*e71b7053SJung-uk Kim 
133*e71b7053SJung-uk Kim # ifdef REF_PRINT
134*e71b7053SJung-uk Kim #  define REF_PRINT_COUNT(a, b) \
135*e71b7053SJung-uk Kim         fprintf(stderr, "%p:%4d:%s\n", b, b->references, a)
136*e71b7053SJung-uk Kim # else
137*e71b7053SJung-uk Kim #  define REF_PRINT_COUNT(a, b)
138*e71b7053SJung-uk Kim # endif
139*e71b7053SJung-uk Kim 
140*e71b7053SJung-uk Kim #endif
141