1 #ifndef JEMALLOC_INTERNAL_LOCKEDINT_H 2 #define JEMALLOC_INTERNAL_LOCKEDINT_H 3 4 /* 5 * In those architectures that support 64-bit atomics, we use atomic updates for 6 * our 64-bit values. Otherwise, we use a plain uint64_t and synchronize 7 * externally. 8 */ 9 10 typedef struct locked_u64_s locked_u64_t; 11 #ifdef JEMALLOC_ATOMIC_U64 12 struct locked_u64_s { 13 atomic_u64_t val; 14 }; 15 #else 16 /* Must hold the associated mutex. */ 17 struct locked_u64_s { 18 uint64_t val; 19 }; 20 #endif 21 22 typedef struct locked_zu_s locked_zu_t; 23 struct locked_zu_s { 24 atomic_zu_t val; 25 }; 26 27 #ifndef JEMALLOC_ATOMIC_U64 28 # define LOCKEDINT_MTX_DECLARE(name) malloc_mutex_t name; 29 # define LOCKEDINT_MTX_INIT(mu, name, rank, rank_mode) \ 30 malloc_mutex_init(&(mu), name, rank, rank_mode) 31 # define LOCKEDINT_MTX(mtx) (&(mtx)) 32 # define LOCKEDINT_MTX_LOCK(tsdn, mu) malloc_mutex_lock(tsdn, &(mu)) 33 # define LOCKEDINT_MTX_UNLOCK(tsdn, mu) malloc_mutex_unlock(tsdn, &(mu)) 34 # define LOCKEDINT_MTX_PREFORK(tsdn, mu) malloc_mutex_prefork(tsdn, &(mu)) 35 # define LOCKEDINT_MTX_POSTFORK_PARENT(tsdn, mu) \ 36 malloc_mutex_postfork_parent(tsdn, &(mu)) 37 # define LOCKEDINT_MTX_POSTFORK_CHILD(tsdn, mu) \ 38 malloc_mutex_postfork_child(tsdn, &(mu)) 39 #else 40 # define LOCKEDINT_MTX_DECLARE(name) 41 # define LOCKEDINT_MTX(mtx) NULL 42 # define LOCKEDINT_MTX_INIT(mu, name, rank, rank_mode) false 43 # define LOCKEDINT_MTX_LOCK(tsdn, mu) 44 # define LOCKEDINT_MTX_UNLOCK(tsdn, mu) 45 # define LOCKEDINT_MTX_PREFORK(tsdn, mu) 46 # define LOCKEDINT_MTX_POSTFORK_PARENT(tsdn, mu) 47 # define LOCKEDINT_MTX_POSTFORK_CHILD(tsdn, mu) 48 #endif 49 50 #ifdef JEMALLOC_ATOMIC_U64 51 # define LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx) assert((mtx) == NULL) 52 #else 53 # define LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx) \ 54 malloc_mutex_assert_owner(tsdn, (mtx)) 55 #endif 56 57 static inline uint64_t 58 locked_read_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p) { 59 LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx); 60 #ifdef JEMALLOC_ATOMIC_U64 61 return atomic_load_u64(&p->val, ATOMIC_RELAXED); 62 #else 63 return p->val; 64 #endif 65 } 66 67 static inline void 68 locked_inc_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p, 69 uint64_t x) { 70 LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx); 71 #ifdef JEMALLOC_ATOMIC_U64 72 atomic_fetch_add_u64(&p->val, x, ATOMIC_RELAXED); 73 #else 74 p->val += x; 75 #endif 76 } 77 78 static inline void 79 locked_dec_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p, 80 uint64_t x) { 81 LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx); 82 #ifdef JEMALLOC_ATOMIC_U64 83 uint64_t r = atomic_fetch_sub_u64(&p->val, x, ATOMIC_RELAXED); 84 assert(r - x <= r); 85 #else 86 p->val -= x; 87 assert(p->val + x >= p->val); 88 #endif 89 } 90 91 /* Increment and take modulus. Returns whether the modulo made any change. */ 92 static inline bool 93 locked_inc_mod_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p, 94 const uint64_t x, const uint64_t modulus) { 95 LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx); 96 uint64_t before, after; 97 bool overflow; 98 #ifdef JEMALLOC_ATOMIC_U64 99 before = atomic_load_u64(&p->val, ATOMIC_RELAXED); 100 do { 101 after = before + x; 102 assert(after >= before); 103 overflow = (after >= modulus); 104 if (overflow) { 105 after %= modulus; 106 } 107 } while (!atomic_compare_exchange_weak_u64(&p->val, &before, after, 108 ATOMIC_RELAXED, ATOMIC_RELAXED)); 109 #else 110 before = p->val; 111 after = before + x; 112 overflow = (after >= modulus); 113 if (overflow) { 114 after %= modulus; 115 } 116 p->val = after; 117 #endif 118 return overflow; 119 } 120 121 /* 122 * Non-atomically sets *dst += src. *dst needs external synchronization. 123 * This lets us avoid the cost of a fetch_add when its unnecessary (note that 124 * the types here are atomic). 125 */ 126 static inline void 127 locked_inc_u64_unsynchronized(locked_u64_t *dst, uint64_t src) { 128 #ifdef JEMALLOC_ATOMIC_U64 129 uint64_t cur_dst = atomic_load_u64(&dst->val, ATOMIC_RELAXED); 130 atomic_store_u64(&dst->val, src + cur_dst, ATOMIC_RELAXED); 131 #else 132 dst->val += src; 133 #endif 134 } 135 136 static inline uint64_t 137 locked_read_u64_unsynchronized(locked_u64_t *p) { 138 #ifdef JEMALLOC_ATOMIC_U64 139 return atomic_load_u64(&p->val, ATOMIC_RELAXED); 140 #else 141 return p->val; 142 #endif 143 } 144 145 static inline void 146 locked_init_u64_unsynchronized(locked_u64_t *p, uint64_t x) { 147 #ifdef JEMALLOC_ATOMIC_U64 148 atomic_store_u64(&p->val, x, ATOMIC_RELAXED); 149 #else 150 p->val = x; 151 #endif 152 } 153 154 static inline size_t 155 locked_read_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p) { 156 LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx); 157 #ifdef JEMALLOC_ATOMIC_U64 158 return atomic_load_zu(&p->val, ATOMIC_RELAXED); 159 #else 160 return atomic_load_zu(&p->val, ATOMIC_RELAXED); 161 #endif 162 } 163 164 static inline void 165 locked_inc_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p, 166 size_t x) { 167 LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx); 168 #ifdef JEMALLOC_ATOMIC_U64 169 atomic_fetch_add_zu(&p->val, x, ATOMIC_RELAXED); 170 #else 171 size_t cur = atomic_load_zu(&p->val, ATOMIC_RELAXED); 172 atomic_store_zu(&p->val, cur + x, ATOMIC_RELAXED); 173 #endif 174 } 175 176 static inline void 177 locked_dec_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p, 178 size_t x) { 179 LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx); 180 #ifdef JEMALLOC_ATOMIC_U64 181 size_t r = atomic_fetch_sub_zu(&p->val, x, ATOMIC_RELAXED); 182 assert(r - x <= r); 183 #else 184 size_t cur = atomic_load_zu(&p->val, ATOMIC_RELAXED); 185 atomic_store_zu(&p->val, cur - x, ATOMIC_RELAXED); 186 #endif 187 } 188 189 /* Like the _u64 variant, needs an externally synchronized *dst. */ 190 static inline void 191 locked_inc_zu_unsynchronized(locked_zu_t *dst, size_t src) { 192 size_t cur_dst = atomic_load_zu(&dst->val, ATOMIC_RELAXED); 193 atomic_store_zu(&dst->val, src + cur_dst, ATOMIC_RELAXED); 194 } 195 196 /* 197 * Unlike the _u64 variant, this is safe to call unconditionally. 198 */ 199 static inline size_t 200 locked_read_atomic_zu(locked_zu_t *p) { 201 return atomic_load_zu(&p->val, ATOMIC_RELAXED); 202 } 203 204 #endif /* JEMALLOC_INTERNAL_LOCKEDINT_H */ 205