1*f6217f89SApple OSS Distributions #if KERNEL
2*f6217f89SApple OSS Distributions #include <kern/assert.h>
3*f6217f89SApple OSS Distributions #include <kern/debug.h>
4*f6217f89SApple OSS Distributions #include <pexpert/pexpert.h>
5*f6217f89SApple OSS Distributions #include <kern/btlog.h>
6*f6217f89SApple OSS Distributions #include <kern/backtrace.h>
7*f6217f89SApple OSS Distributions #include <kern/zalloc.h>
8*f6217f89SApple OSS Distributions #include <kern/sched_prim.h>
9*f6217f89SApple OSS Distributions #include <libkern/libkern.h>
10*f6217f89SApple OSS Distributions #endif
11*f6217f89SApple OSS Distributions #include <os/overflow.h>
12*f6217f89SApple OSS Distributions #include <os/atomic_private.h>
13*f6217f89SApple OSS Distributions
14*f6217f89SApple OSS Distributions #include "refcnt.h"
15*f6217f89SApple OSS Distributions
16*f6217f89SApple OSS Distributions #define OS_REFCNT_MAX_COUNT ((os_ref_count_t)0x0FFFFFFFUL)
17*f6217f89SApple OSS Distributions
18*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
19*f6217f89SApple OSS Distributions extern struct os_refgrp global_ref_group;
20*f6217f89SApple OSS Distributions os_refgrp_decl(, global_ref_group, "all", NULL);
21*f6217f89SApple OSS Distributions
22*f6217f89SApple OSS Distributions extern bool ref_debug_enable;
23*f6217f89SApple OSS Distributions bool ref_debug_enable = false;
24*f6217f89SApple OSS Distributions
25*f6217f89SApple OSS Distributions #define REFLOG_GRP_DEBUG_ENABLED(grp) \
26*f6217f89SApple OSS Distributions __improbable(grp != NULL && (ref_debug_enable || \
27*f6217f89SApple OSS Distributions (grp->grp_flags & OS_REFGRP_F_ALWAYS_ENABLED) != 0))
28*f6217f89SApple OSS Distributions
29*f6217f89SApple OSS Distributions static const size_t ref_log_nrecords = 1000000;
30*f6217f89SApple OSS Distributions
31*f6217f89SApple OSS Distributions __enum_closed_decl(reflog_op_t, uint8_t, {
32*f6217f89SApple OSS Distributions REFLOG_RETAIN = 1,
33*f6217f89SApple OSS Distributions REFLOG_RELEASE = 2
34*f6217f89SApple OSS Distributions });
35*f6217f89SApple OSS Distributions
36*f6217f89SApple OSS Distributions # define __debug_only
37*f6217f89SApple OSS Distributions # define __os_refgrp_arg(arg) , arg
38*f6217f89SApple OSS Distributions #else
39*f6217f89SApple OSS Distributions # define __debug_only __unused
40*f6217f89SApple OSS Distributions # define __os_refgrp_arg(arg)
41*f6217f89SApple OSS Distributions #endif /* OS_REFCNT_DEBUG */
42*f6217f89SApple OSS Distributions
43*f6217f89SApple OSS Distributions void
os_ref_panic_live(void * rc)44*f6217f89SApple OSS Distributions os_ref_panic_live(void *rc)
45*f6217f89SApple OSS Distributions {
46*f6217f89SApple OSS Distributions panic("os_refcnt: unexpected release of final reference (rc=%p)", rc);
47*f6217f89SApple OSS Distributions __builtin_unreachable();
48*f6217f89SApple OSS Distributions }
49*f6217f89SApple OSS Distributions void
os_ref_panic_last(void * rc)50*f6217f89SApple OSS Distributions os_ref_panic_last(void *rc)
51*f6217f89SApple OSS Distributions {
52*f6217f89SApple OSS Distributions panic("os_refcnt: expected release of final reference but rc %p!=0\n", rc);
53*f6217f89SApple OSS Distributions __builtin_unreachable();
54*f6217f89SApple OSS Distributions }
55*f6217f89SApple OSS Distributions
56*f6217f89SApple OSS Distributions __abortlike
57*f6217f89SApple OSS Distributions static void
os_ref_panic_underflow(void * rc)58*f6217f89SApple OSS Distributions os_ref_panic_underflow(void *rc)
59*f6217f89SApple OSS Distributions {
60*f6217f89SApple OSS Distributions panic("os_refcnt: underflow (rc=%p)", rc);
61*f6217f89SApple OSS Distributions __builtin_unreachable();
62*f6217f89SApple OSS Distributions }
63*f6217f89SApple OSS Distributions
64*f6217f89SApple OSS Distributions __abortlike
65*f6217f89SApple OSS Distributions static void
os_ref_panic_overflow(os_ref_atomic_t * rc)66*f6217f89SApple OSS Distributions os_ref_panic_overflow(os_ref_atomic_t *rc)
67*f6217f89SApple OSS Distributions {
68*f6217f89SApple OSS Distributions panic("os_refcnt: overflow (rc=%p, count=%u, max=%u)", rc, os_atomic_load(rc, relaxed), OS_REFCNT_MAX_COUNT);
69*f6217f89SApple OSS Distributions __builtin_unreachable();
70*f6217f89SApple OSS Distributions }
71*f6217f89SApple OSS Distributions
72*f6217f89SApple OSS Distributions __abortlike
73*f6217f89SApple OSS Distributions static void
os_ref_panic_retain(os_ref_atomic_t * rc)74*f6217f89SApple OSS Distributions os_ref_panic_retain(os_ref_atomic_t *rc)
75*f6217f89SApple OSS Distributions {
76*f6217f89SApple OSS Distributions if (os_atomic_load(rc, relaxed) >= OS_REFCNT_MAX_COUNT) {
77*f6217f89SApple OSS Distributions os_ref_panic_overflow(rc);
78*f6217f89SApple OSS Distributions } else {
79*f6217f89SApple OSS Distributions panic("os_refcnt: attempted resurrection (rc=%p)", rc);
80*f6217f89SApple OSS Distributions }
81*f6217f89SApple OSS Distributions }
82*f6217f89SApple OSS Distributions
83*f6217f89SApple OSS Distributions static inline void
os_ref_check_underflow(void * rc,os_ref_count_t count,os_ref_count_t n)84*f6217f89SApple OSS Distributions os_ref_check_underflow(void *rc, os_ref_count_t count, os_ref_count_t n)
85*f6217f89SApple OSS Distributions {
86*f6217f89SApple OSS Distributions if (__improbable(count < n)) {
87*f6217f89SApple OSS Distributions os_ref_panic_underflow(rc);
88*f6217f89SApple OSS Distributions }
89*f6217f89SApple OSS Distributions }
90*f6217f89SApple OSS Distributions
91*f6217f89SApple OSS Distributions static inline void
os_ref_check_overflow(os_ref_atomic_t * rc,os_ref_count_t count)92*f6217f89SApple OSS Distributions os_ref_check_overflow(os_ref_atomic_t *rc, os_ref_count_t count)
93*f6217f89SApple OSS Distributions {
94*f6217f89SApple OSS Distributions if (__improbable(count >= OS_REFCNT_MAX_COUNT)) {
95*f6217f89SApple OSS Distributions os_ref_panic_overflow(rc);
96*f6217f89SApple OSS Distributions }
97*f6217f89SApple OSS Distributions }
98*f6217f89SApple OSS Distributions
99*f6217f89SApple OSS Distributions static inline void
os_ref_check_retain(os_ref_atomic_t * rc,os_ref_count_t count,os_ref_count_t n)100*f6217f89SApple OSS Distributions os_ref_check_retain(os_ref_atomic_t *rc, os_ref_count_t count, os_ref_count_t n)
101*f6217f89SApple OSS Distributions {
102*f6217f89SApple OSS Distributions if (__improbable(count < n || count >= OS_REFCNT_MAX_COUNT)) {
103*f6217f89SApple OSS Distributions os_ref_panic_retain(rc);
104*f6217f89SApple OSS Distributions }
105*f6217f89SApple OSS Distributions }
106*f6217f89SApple OSS Distributions
107*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
108*f6217f89SApple OSS Distributions #if KERNEL
109*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
110*f6217f89SApple OSS Distributions static void
ref_log_op(struct os_refgrp * grp,void * elem,reflog_op_t op)111*f6217f89SApple OSS Distributions ref_log_op(struct os_refgrp *grp, void *elem, reflog_op_t op)
112*f6217f89SApple OSS Distributions {
113*f6217f89SApple OSS Distributions if (grp == NULL) {
114*f6217f89SApple OSS Distributions return;
115*f6217f89SApple OSS Distributions }
116*f6217f89SApple OSS Distributions
117*f6217f89SApple OSS Distributions if (grp->grp_log == NULL) {
118*f6217f89SApple OSS Distributions ref_log_op(grp->grp_parent, elem, op);
119*f6217f89SApple OSS Distributions return;
120*f6217f89SApple OSS Distributions }
121*f6217f89SApple OSS Distributions
122*f6217f89SApple OSS Distributions btlog_record((btlog_t)grp->grp_log, elem, op,
123*f6217f89SApple OSS Distributions btref_get(__builtin_frame_address(0), BTREF_GET_NOWAIT));
124*f6217f89SApple OSS Distributions }
125*f6217f89SApple OSS Distributions
126*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
127*f6217f89SApple OSS Distributions static void
ref_log_drop(struct os_refgrp * grp,void * elem)128*f6217f89SApple OSS Distributions ref_log_drop(struct os_refgrp *grp, void *elem)
129*f6217f89SApple OSS Distributions {
130*f6217f89SApple OSS Distributions if (!REFLOG_GRP_DEBUG_ENABLED(grp)) {
131*f6217f89SApple OSS Distributions return;
132*f6217f89SApple OSS Distributions }
133*f6217f89SApple OSS Distributions
134*f6217f89SApple OSS Distributions if (grp->grp_log == NULL) {
135*f6217f89SApple OSS Distributions ref_log_drop(grp->grp_parent, elem);
136*f6217f89SApple OSS Distributions return;
137*f6217f89SApple OSS Distributions }
138*f6217f89SApple OSS Distributions
139*f6217f89SApple OSS Distributions btlog_erase(grp->grp_log, elem);
140*f6217f89SApple OSS Distributions }
141*f6217f89SApple OSS Distributions
142*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
143*f6217f89SApple OSS Distributions void
os_ref_log_init(struct os_refgrp * grp)144*f6217f89SApple OSS Distributions os_ref_log_init(struct os_refgrp *grp)
145*f6217f89SApple OSS Distributions {
146*f6217f89SApple OSS Distributions if (grp->grp_log != NULL) {
147*f6217f89SApple OSS Distributions return;
148*f6217f89SApple OSS Distributions }
149*f6217f89SApple OSS Distributions
150*f6217f89SApple OSS Distributions char grpbuf[128];
151*f6217f89SApple OSS Distributions char *refgrp = grpbuf;
152*f6217f89SApple OSS Distributions if (!PE_parse_boot_argn("rlog", refgrp, sizeof(grpbuf))) {
153*f6217f89SApple OSS Distributions return;
154*f6217f89SApple OSS Distributions }
155*f6217f89SApple OSS Distributions
156*f6217f89SApple OSS Distributions /*
157*f6217f89SApple OSS Distributions * Enable refcount statistics if the rlog boot-arg is present,
158*f6217f89SApple OSS Distributions * even when no specific group is logged.
159*f6217f89SApple OSS Distributions */
160*f6217f89SApple OSS Distributions ref_debug_enable = true;
161*f6217f89SApple OSS Distributions
162*f6217f89SApple OSS Distributions const char *g;
163*f6217f89SApple OSS Distributions while ((g = strsep(&refgrp, ",")) != NULL) {
164*f6217f89SApple OSS Distributions if (strcmp(g, grp->grp_name) == 0) {
165*f6217f89SApple OSS Distributions /* enable logging on this refgrp */
166*f6217f89SApple OSS Distributions grp->grp_log = btlog_create(BTLOG_HASH,
167*f6217f89SApple OSS Distributions ref_log_nrecords, 0);
168*f6217f89SApple OSS Distributions return;
169*f6217f89SApple OSS Distributions }
170*f6217f89SApple OSS Distributions }
171*f6217f89SApple OSS Distributions }
172*f6217f89SApple OSS Distributions
173*f6217f89SApple OSS Distributions
174*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
175*f6217f89SApple OSS Distributions void
os_ref_log_fini(struct os_refgrp * grp)176*f6217f89SApple OSS Distributions os_ref_log_fini(struct os_refgrp *grp)
177*f6217f89SApple OSS Distributions {
178*f6217f89SApple OSS Distributions if (grp->grp_log == NULL) {
179*f6217f89SApple OSS Distributions return;
180*f6217f89SApple OSS Distributions }
181*f6217f89SApple OSS Distributions
182*f6217f89SApple OSS Distributions btlog_destroy(grp->grp_log);
183*f6217f89SApple OSS Distributions grp->grp_log = NULL;
184*f6217f89SApple OSS Distributions }
185*f6217f89SApple OSS Distributions
186*f6217f89SApple OSS Distributions #else
187*f6217f89SApple OSS Distributions
188*f6217f89SApple OSS Distributions #ifndef os_ref_log_fini
189*f6217f89SApple OSS Distributions inline void
os_ref_log_fini(struct os_refgrp * grp __unused)190*f6217f89SApple OSS Distributions os_ref_log_fini(struct os_refgrp *grp __unused)
191*f6217f89SApple OSS Distributions {
192*f6217f89SApple OSS Distributions }
193*f6217f89SApple OSS Distributions #endif
194*f6217f89SApple OSS Distributions
195*f6217f89SApple OSS Distributions #ifndef os_ref_log_init
196*f6217f89SApple OSS Distributions inline void
os_ref_log_init(struct os_refgrp * grp __unused)197*f6217f89SApple OSS Distributions os_ref_log_init(struct os_refgrp *grp __unused)
198*f6217f89SApple OSS Distributions {
199*f6217f89SApple OSS Distributions }
200*f6217f89SApple OSS Distributions #endif
201*f6217f89SApple OSS Distributions #ifndef ref_log_op
202*f6217f89SApple OSS Distributions static inline void
ref_log_op(struct os_refgrp * grp __unused,void * rc __unused,reflog_op_t op __unused)203*f6217f89SApple OSS Distributions ref_log_op(struct os_refgrp *grp __unused, void *rc __unused, reflog_op_t op __unused)
204*f6217f89SApple OSS Distributions {
205*f6217f89SApple OSS Distributions }
206*f6217f89SApple OSS Distributions #endif
207*f6217f89SApple OSS Distributions #ifndef ref_log_drop
208*f6217f89SApple OSS Distributions static inline void
ref_log_drop(struct os_refgrp * grp __unused,void * rc __unused)209*f6217f89SApple OSS Distributions ref_log_drop(struct os_refgrp *grp __unused, void *rc __unused)
210*f6217f89SApple OSS Distributions {
211*f6217f89SApple OSS Distributions }
212*f6217f89SApple OSS Distributions #endif
213*f6217f89SApple OSS Distributions
214*f6217f89SApple OSS Distributions #endif /* KERNEL */
215*f6217f89SApple OSS Distributions
216*f6217f89SApple OSS Distributions /*
217*f6217f89SApple OSS Distributions * attach a new refcnt to a group
218*f6217f89SApple OSS Distributions */
219*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
220*f6217f89SApple OSS Distributions static void
ref_attach_to_group(os_ref_atomic_t * rc,struct os_refgrp * grp,os_ref_count_t init_count)221*f6217f89SApple OSS Distributions ref_attach_to_group(os_ref_atomic_t *rc, struct os_refgrp *grp, os_ref_count_t init_count)
222*f6217f89SApple OSS Distributions {
223*f6217f89SApple OSS Distributions if (grp == NULL) {
224*f6217f89SApple OSS Distributions return;
225*f6217f89SApple OSS Distributions }
226*f6217f89SApple OSS Distributions
227*f6217f89SApple OSS Distributions if (atomic_fetch_add_explicit(&grp->grp_children, 1, memory_order_relaxed) == 0) {
228*f6217f89SApple OSS Distributions /* First reference count object in this group. Check if we should enable
229*f6217f89SApple OSS Distributions * refcount logging. */
230*f6217f89SApple OSS Distributions os_ref_log_init(grp);
231*f6217f89SApple OSS Distributions }
232*f6217f89SApple OSS Distributions
233*f6217f89SApple OSS Distributions atomic_fetch_add_explicit(&grp->grp_count, init_count, memory_order_relaxed);
234*f6217f89SApple OSS Distributions atomic_fetch_add_explicit(&grp->grp_retain_total, init_count, memory_order_relaxed);
235*f6217f89SApple OSS Distributions
236*f6217f89SApple OSS Distributions if (grp == &global_ref_group) {
237*f6217f89SApple OSS Distributions return;
238*f6217f89SApple OSS Distributions }
239*f6217f89SApple OSS Distributions
240*f6217f89SApple OSS Distributions if (grp->grp_parent == NULL) {
241*f6217f89SApple OSS Distributions grp->grp_parent = &global_ref_group;
242*f6217f89SApple OSS Distributions }
243*f6217f89SApple OSS Distributions
244*f6217f89SApple OSS Distributions ref_attach_to_group(rc, grp->grp_parent, init_count);
245*f6217f89SApple OSS Distributions }
246*f6217f89SApple OSS Distributions
247*f6217f89SApple OSS Distributions static void
ref_retain_group(struct os_refgrp * grp)248*f6217f89SApple OSS Distributions ref_retain_group(struct os_refgrp *grp)
249*f6217f89SApple OSS Distributions {
250*f6217f89SApple OSS Distributions if (grp) {
251*f6217f89SApple OSS Distributions atomic_fetch_add_explicit(&grp->grp_count, 1, memory_order_relaxed);
252*f6217f89SApple OSS Distributions atomic_fetch_add_explicit(&grp->grp_retain_total, 1, memory_order_relaxed);
253*f6217f89SApple OSS Distributions ref_retain_group(grp->grp_parent);
254*f6217f89SApple OSS Distributions }
255*f6217f89SApple OSS Distributions }
256*f6217f89SApple OSS Distributions
257*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
258*f6217f89SApple OSS Distributions static void
ref_release_group(struct os_refgrp * grp)259*f6217f89SApple OSS Distributions ref_release_group(struct os_refgrp *grp)
260*f6217f89SApple OSS Distributions {
261*f6217f89SApple OSS Distributions if (grp) {
262*f6217f89SApple OSS Distributions atomic_fetch_sub_explicit(&grp->grp_count, 1, memory_order_relaxed);
263*f6217f89SApple OSS Distributions atomic_fetch_add_explicit(&grp->grp_release_total, 1, memory_order_relaxed);
264*f6217f89SApple OSS Distributions
265*f6217f89SApple OSS Distributions ref_release_group(grp->grp_parent);
266*f6217f89SApple OSS Distributions }
267*f6217f89SApple OSS Distributions }
268*f6217f89SApple OSS Distributions
269*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
270*f6217f89SApple OSS Distributions static void
ref_drop_group(struct os_refgrp * grp)271*f6217f89SApple OSS Distributions ref_drop_group(struct os_refgrp *grp)
272*f6217f89SApple OSS Distributions {
273*f6217f89SApple OSS Distributions if (grp) {
274*f6217f89SApple OSS Distributions atomic_fetch_sub_explicit(&grp->grp_children, 1, memory_order_relaxed);
275*f6217f89SApple OSS Distributions ref_drop_group(grp->grp_parent);
276*f6217f89SApple OSS Distributions }
277*f6217f89SApple OSS Distributions }
278*f6217f89SApple OSS Distributions
279*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
280*f6217f89SApple OSS Distributions static void
ref_init_debug(void * rc,struct os_refgrp * grp,os_ref_count_t count)281*f6217f89SApple OSS Distributions ref_init_debug(void *rc, struct os_refgrp *grp, os_ref_count_t count)
282*f6217f89SApple OSS Distributions {
283*f6217f89SApple OSS Distributions ref_attach_to_group(rc, grp, count);
284*f6217f89SApple OSS Distributions
285*f6217f89SApple OSS Distributions for (os_ref_count_t i = 0; i < count; i++) {
286*f6217f89SApple OSS Distributions ref_log_op(grp, rc, REFLOG_RETAIN);
287*f6217f89SApple OSS Distributions }
288*f6217f89SApple OSS Distributions }
289*f6217f89SApple OSS Distributions
290*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
291*f6217f89SApple OSS Distributions static void
ref_retain_debug(void * rc,struct os_refgrp * __debug_only grp)292*f6217f89SApple OSS Distributions ref_retain_debug(void *rc, struct os_refgrp * __debug_only grp)
293*f6217f89SApple OSS Distributions {
294*f6217f89SApple OSS Distributions ref_retain_group(grp);
295*f6217f89SApple OSS Distributions ref_log_op(grp, rc, REFLOG_RETAIN);
296*f6217f89SApple OSS Distributions }
297*f6217f89SApple OSS Distributions
298*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
299*f6217f89SApple OSS Distributions static void
ref_release_debug(void * rc,struct os_refgrp * __debug_only grp)300*f6217f89SApple OSS Distributions ref_release_debug(void *rc, struct os_refgrp * __debug_only grp)
301*f6217f89SApple OSS Distributions {
302*f6217f89SApple OSS Distributions ref_log_op(grp, rc, REFLOG_RELEASE);
303*f6217f89SApple OSS Distributions ref_release_group(grp);
304*f6217f89SApple OSS Distributions }
305*f6217f89SApple OSS Distributions
306*f6217f89SApple OSS Distributions __attribute__((cold, noinline))
307*f6217f89SApple OSS Distributions static os_ref_count_t
ref_drop_debug(void * rc,struct os_refgrp * __debug_only grp)308*f6217f89SApple OSS Distributions ref_drop_debug(void *rc, struct os_refgrp * __debug_only grp)
309*f6217f89SApple OSS Distributions {
310*f6217f89SApple OSS Distributions ref_log_drop(grp, rc);
311*f6217f89SApple OSS Distributions ref_drop_group(grp);
312*f6217f89SApple OSS Distributions return 0;
313*f6217f89SApple OSS Distributions }
314*f6217f89SApple OSS Distributions #endif
315*f6217f89SApple OSS Distributions
316*f6217f89SApple OSS Distributions void
os_ref_init_count_internal(os_ref_atomic_t * rc,struct os_refgrp * __debug_only grp,os_ref_count_t count)317*f6217f89SApple OSS Distributions os_ref_init_count_internal(os_ref_atomic_t *rc, struct os_refgrp * __debug_only grp, os_ref_count_t count)
318*f6217f89SApple OSS Distributions {
319*f6217f89SApple OSS Distributions os_ref_check_underflow(rc, count, 1);
320*f6217f89SApple OSS Distributions atomic_init(rc, count);
321*f6217f89SApple OSS Distributions
322*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
323*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
324*f6217f89SApple OSS Distributions ref_init_debug(rc, grp, count);
325*f6217f89SApple OSS Distributions }
326*f6217f89SApple OSS Distributions #endif
327*f6217f89SApple OSS Distributions }
328*f6217f89SApple OSS Distributions
329*f6217f89SApple OSS Distributions static inline void
__os_ref_retain(os_ref_atomic_t * rc,os_ref_count_t f,struct os_refgrp * __debug_only grp)330*f6217f89SApple OSS Distributions __os_ref_retain(os_ref_atomic_t *rc, os_ref_count_t f,
331*f6217f89SApple OSS Distributions struct os_refgrp * __debug_only grp)
332*f6217f89SApple OSS Distributions {
333*f6217f89SApple OSS Distributions os_ref_count_t old = atomic_fetch_add_explicit(rc, 1, memory_order_relaxed);
334*f6217f89SApple OSS Distributions os_ref_check_retain(rc, old, f);
335*f6217f89SApple OSS Distributions
336*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
337*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
338*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
339*f6217f89SApple OSS Distributions }
340*f6217f89SApple OSS Distributions #endif
341*f6217f89SApple OSS Distributions }
342*f6217f89SApple OSS Distributions
343*f6217f89SApple OSS Distributions void
os_ref_retain_internal(os_ref_atomic_t * rc,struct os_refgrp * grp)344*f6217f89SApple OSS Distributions os_ref_retain_internal(os_ref_atomic_t *rc, struct os_refgrp *grp)
345*f6217f89SApple OSS Distributions {
346*f6217f89SApple OSS Distributions __os_ref_retain(rc, 1, grp);
347*f6217f89SApple OSS Distributions }
348*f6217f89SApple OSS Distributions
349*f6217f89SApple OSS Distributions void
os_ref_retain_floor_internal(os_ref_atomic_t * rc,os_ref_count_t f,struct os_refgrp * grp)350*f6217f89SApple OSS Distributions os_ref_retain_floor_internal(os_ref_atomic_t *rc, os_ref_count_t f,
351*f6217f89SApple OSS Distributions struct os_refgrp *grp)
352*f6217f89SApple OSS Distributions {
353*f6217f89SApple OSS Distributions __os_ref_retain(rc, f, grp);
354*f6217f89SApple OSS Distributions }
355*f6217f89SApple OSS Distributions
356*f6217f89SApple OSS Distributions static inline bool
__os_ref_retain_try(os_ref_atomic_t * rc,os_ref_count_t f,struct os_refgrp * __debug_only grp)357*f6217f89SApple OSS Distributions __os_ref_retain_try(os_ref_atomic_t *rc, os_ref_count_t f,
358*f6217f89SApple OSS Distributions struct os_refgrp * __debug_only grp)
359*f6217f89SApple OSS Distributions {
360*f6217f89SApple OSS Distributions os_ref_count_t cur, next;
361*f6217f89SApple OSS Distributions
362*f6217f89SApple OSS Distributions os_atomic_rmw_loop(rc, cur, next, relaxed, {
363*f6217f89SApple OSS Distributions if (__improbable(cur < f)) {
364*f6217f89SApple OSS Distributions os_atomic_rmw_loop_give_up(return false);
365*f6217f89SApple OSS Distributions }
366*f6217f89SApple OSS Distributions
367*f6217f89SApple OSS Distributions next = cur + 1;
368*f6217f89SApple OSS Distributions });
369*f6217f89SApple OSS Distributions
370*f6217f89SApple OSS Distributions os_ref_check_overflow(rc, cur);
371*f6217f89SApple OSS Distributions
372*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
373*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
374*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
375*f6217f89SApple OSS Distributions }
376*f6217f89SApple OSS Distributions #endif
377*f6217f89SApple OSS Distributions
378*f6217f89SApple OSS Distributions return true;
379*f6217f89SApple OSS Distributions }
380*f6217f89SApple OSS Distributions
381*f6217f89SApple OSS Distributions bool
os_ref_retain_try_internal(os_ref_atomic_t * rc,struct os_refgrp * grp)382*f6217f89SApple OSS Distributions os_ref_retain_try_internal(os_ref_atomic_t *rc, struct os_refgrp *grp)
383*f6217f89SApple OSS Distributions {
384*f6217f89SApple OSS Distributions return __os_ref_retain_try(rc, 1, grp);
385*f6217f89SApple OSS Distributions }
386*f6217f89SApple OSS Distributions
387*f6217f89SApple OSS Distributions bool
os_ref_retain_floor_try_internal(os_ref_atomic_t * rc,os_ref_count_t f,struct os_refgrp * grp)388*f6217f89SApple OSS Distributions os_ref_retain_floor_try_internal(os_ref_atomic_t *rc, os_ref_count_t f,
389*f6217f89SApple OSS Distributions struct os_refgrp *grp)
390*f6217f89SApple OSS Distributions {
391*f6217f89SApple OSS Distributions return __os_ref_retain_try(rc, f, grp);
392*f6217f89SApple OSS Distributions }
393*f6217f89SApple OSS Distributions
394*f6217f89SApple OSS Distributions __attribute__((always_inline))
395*f6217f89SApple OSS Distributions static inline os_ref_count_t
_os_ref_release_inline(os_ref_atomic_t * rc,os_ref_count_t n,struct os_refgrp * __debug_only grp,memory_order release_order,memory_order dealloc_order)396*f6217f89SApple OSS Distributions _os_ref_release_inline(os_ref_atomic_t *rc, os_ref_count_t n,
397*f6217f89SApple OSS Distributions struct os_refgrp * __debug_only grp,
398*f6217f89SApple OSS Distributions memory_order release_order, memory_order dealloc_order)
399*f6217f89SApple OSS Distributions {
400*f6217f89SApple OSS Distributions os_ref_count_t val;
401*f6217f89SApple OSS Distributions
402*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
403*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
404*f6217f89SApple OSS Distributions /*
405*f6217f89SApple OSS Distributions * Care not to use 'rc' after the decrement because it might be deallocated
406*f6217f89SApple OSS Distributions * under us.
407*f6217f89SApple OSS Distributions */
408*f6217f89SApple OSS Distributions ref_release_debug(rc, grp);
409*f6217f89SApple OSS Distributions }
410*f6217f89SApple OSS Distributions #endif
411*f6217f89SApple OSS Distributions
412*f6217f89SApple OSS Distributions val = atomic_fetch_sub_explicit(rc, n, release_order);
413*f6217f89SApple OSS Distributions os_ref_check_underflow(rc, val, n);
414*f6217f89SApple OSS Distributions val -= n;
415*f6217f89SApple OSS Distributions if (__improbable(val < n)) {
416*f6217f89SApple OSS Distributions atomic_load_explicit(rc, dealloc_order);
417*f6217f89SApple OSS Distributions }
418*f6217f89SApple OSS Distributions
419*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
420*f6217f89SApple OSS Distributions /*
421*f6217f89SApple OSS Distributions * The only way to safely access the ref count or group after
422*f6217f89SApple OSS Distributions * decrementing the count is when the count is zero (as the caller won't
423*f6217f89SApple OSS Distributions * see the zero until the function returns).
424*f6217f89SApple OSS Distributions */
425*f6217f89SApple OSS Distributions if (val == 0 && REFLOG_GRP_DEBUG_ENABLED(grp)) {
426*f6217f89SApple OSS Distributions return ref_drop_debug(rc, grp);
427*f6217f89SApple OSS Distributions }
428*f6217f89SApple OSS Distributions #endif
429*f6217f89SApple OSS Distributions
430*f6217f89SApple OSS Distributions return val;
431*f6217f89SApple OSS Distributions }
432*f6217f89SApple OSS Distributions
433*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
434*f6217f89SApple OSS Distributions __attribute__((noinline))
435*f6217f89SApple OSS Distributions static os_ref_count_t
os_ref_release_n_internal(os_ref_atomic_t * rc,os_ref_count_t n,struct os_refgrp * __debug_only grp,memory_order release_order,memory_order dealloc_order)436*f6217f89SApple OSS Distributions os_ref_release_n_internal(os_ref_atomic_t *rc, os_ref_count_t n,
437*f6217f89SApple OSS Distributions struct os_refgrp * __debug_only grp,
438*f6217f89SApple OSS Distributions memory_order release_order, memory_order dealloc_order)
439*f6217f89SApple OSS Distributions {
440*f6217f89SApple OSS Distributions // Legacy exported interface with bad codegen due to the barriers
441*f6217f89SApple OSS Distributions // not being immediate
442*f6217f89SApple OSS Distributions //
443*f6217f89SApple OSS Distributions // Also serves as the debug function
444*f6217f89SApple OSS Distributions return _os_ref_release_inline(rc, n, grp, release_order, dealloc_order);
445*f6217f89SApple OSS Distributions }
446*f6217f89SApple OSS Distributions #endif
447*f6217f89SApple OSS Distributions
448*f6217f89SApple OSS Distributions __attribute__((noinline))
449*f6217f89SApple OSS Distributions os_ref_count_t
os_ref_release_internal(os_ref_atomic_t * rc,struct os_refgrp * __debug_only grp,memory_order release_order,memory_order dealloc_order)450*f6217f89SApple OSS Distributions os_ref_release_internal(os_ref_atomic_t *rc, struct os_refgrp * __debug_only grp,
451*f6217f89SApple OSS Distributions memory_order release_order, memory_order dealloc_order)
452*f6217f89SApple OSS Distributions {
453*f6217f89SApple OSS Distributions // Legacy exported interface with bad codegen due to the barriers
454*f6217f89SApple OSS Distributions // not being immediate
455*f6217f89SApple OSS Distributions //
456*f6217f89SApple OSS Distributions // Also serves as the debug function
457*f6217f89SApple OSS Distributions return _os_ref_release_inline(rc, 1, grp, release_order, dealloc_order);
458*f6217f89SApple OSS Distributions }
459*f6217f89SApple OSS Distributions
460*f6217f89SApple OSS Distributions os_ref_count_t
os_ref_release_barrier_internal(os_ref_atomic_t * rc,struct os_refgrp * __debug_only grp)461*f6217f89SApple OSS Distributions os_ref_release_barrier_internal(os_ref_atomic_t *rc,
462*f6217f89SApple OSS Distributions struct os_refgrp * __debug_only grp)
463*f6217f89SApple OSS Distributions {
464*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
465*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
466*f6217f89SApple OSS Distributions return os_ref_release_internal(rc, grp,
467*f6217f89SApple OSS Distributions memory_order_release, memory_order_acquire);
468*f6217f89SApple OSS Distributions }
469*f6217f89SApple OSS Distributions #endif
470*f6217f89SApple OSS Distributions return _os_ref_release_inline(rc, 1, NULL,
471*f6217f89SApple OSS Distributions memory_order_release, memory_order_acquire);
472*f6217f89SApple OSS Distributions }
473*f6217f89SApple OSS Distributions
474*f6217f89SApple OSS Distributions os_ref_count_t
os_ref_release_relaxed_internal(os_ref_atomic_t * rc,struct os_refgrp * __debug_only grp)475*f6217f89SApple OSS Distributions os_ref_release_relaxed_internal(os_ref_atomic_t *rc,
476*f6217f89SApple OSS Distributions struct os_refgrp * __debug_only grp)
477*f6217f89SApple OSS Distributions {
478*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
479*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
480*f6217f89SApple OSS Distributions return os_ref_release_internal(rc, grp,
481*f6217f89SApple OSS Distributions memory_order_relaxed, memory_order_relaxed);
482*f6217f89SApple OSS Distributions }
483*f6217f89SApple OSS Distributions #endif
484*f6217f89SApple OSS Distributions return _os_ref_release_inline(rc, 1, NULL,
485*f6217f89SApple OSS Distributions memory_order_relaxed, memory_order_relaxed);
486*f6217f89SApple OSS Distributions }
487*f6217f89SApple OSS Distributions
488*f6217f89SApple OSS Distributions static inline void
__os_ref_retain_locked(os_ref_atomic_t * rc,os_ref_count_t f,struct os_refgrp * __debug_only grp)489*f6217f89SApple OSS Distributions __os_ref_retain_locked(os_ref_atomic_t *rc, os_ref_count_t f,
490*f6217f89SApple OSS Distributions struct os_refgrp * __debug_only grp)
491*f6217f89SApple OSS Distributions {
492*f6217f89SApple OSS Distributions os_ref_count_t val = os_ref_get_count_internal(rc);
493*f6217f89SApple OSS Distributions os_ref_check_retain(rc, val, f);
494*f6217f89SApple OSS Distributions atomic_store_explicit(rc, ++val, memory_order_relaxed);
495*f6217f89SApple OSS Distributions
496*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
497*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
498*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
499*f6217f89SApple OSS Distributions }
500*f6217f89SApple OSS Distributions #endif
501*f6217f89SApple OSS Distributions }
502*f6217f89SApple OSS Distributions
503*f6217f89SApple OSS Distributions void
os_ref_retain_locked_internal(os_ref_atomic_t * rc,struct os_refgrp * grp)504*f6217f89SApple OSS Distributions os_ref_retain_locked_internal(os_ref_atomic_t *rc, struct os_refgrp *grp)
505*f6217f89SApple OSS Distributions {
506*f6217f89SApple OSS Distributions __os_ref_retain_locked(rc, 1, grp);
507*f6217f89SApple OSS Distributions }
508*f6217f89SApple OSS Distributions
509*f6217f89SApple OSS Distributions void
os_ref_retain_floor_locked_internal(os_ref_atomic_t * rc,os_ref_count_t f,struct os_refgrp * grp)510*f6217f89SApple OSS Distributions os_ref_retain_floor_locked_internal(os_ref_atomic_t *rc, os_ref_count_t f,
511*f6217f89SApple OSS Distributions struct os_refgrp *grp)
512*f6217f89SApple OSS Distributions {
513*f6217f89SApple OSS Distributions __os_ref_retain_locked(rc, f, grp);
514*f6217f89SApple OSS Distributions }
515*f6217f89SApple OSS Distributions
516*f6217f89SApple OSS Distributions os_ref_count_t
os_ref_release_locked_internal(os_ref_atomic_t * rc,struct os_refgrp * __debug_only grp)517*f6217f89SApple OSS Distributions os_ref_release_locked_internal(os_ref_atomic_t *rc, struct os_refgrp * __debug_only grp)
518*f6217f89SApple OSS Distributions {
519*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
520*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
521*f6217f89SApple OSS Distributions ref_release_debug(rc, grp);
522*f6217f89SApple OSS Distributions }
523*f6217f89SApple OSS Distributions #endif
524*f6217f89SApple OSS Distributions
525*f6217f89SApple OSS Distributions os_ref_count_t val = os_ref_get_count_internal(rc);
526*f6217f89SApple OSS Distributions os_ref_check_underflow(rc, val, 1);
527*f6217f89SApple OSS Distributions atomic_store_explicit(rc, --val, memory_order_relaxed);
528*f6217f89SApple OSS Distributions
529*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
530*f6217f89SApple OSS Distributions if (val == 0 && REFLOG_GRP_DEBUG_ENABLED(grp)) {
531*f6217f89SApple OSS Distributions return ref_drop_debug(rc, grp);
532*f6217f89SApple OSS Distributions }
533*f6217f89SApple OSS Distributions #endif
534*f6217f89SApple OSS Distributions
535*f6217f89SApple OSS Distributions return val;
536*f6217f89SApple OSS Distributions }
537*f6217f89SApple OSS Distributions
538*f6217f89SApple OSS Distributions /*
539*f6217f89SApple OSS Distributions * Bitwise API
540*f6217f89SApple OSS Distributions */
541*f6217f89SApple OSS Distributions
542*f6217f89SApple OSS Distributions #undef os_ref_init_count_mask
543*f6217f89SApple OSS Distributions void
os_ref_init_count_mask(os_ref_atomic_t * rc,uint32_t b,struct os_refgrp * __debug_only grp,os_ref_count_t init_count,uint32_t init_bits)544*f6217f89SApple OSS Distributions os_ref_init_count_mask(os_ref_atomic_t *rc, uint32_t b,
545*f6217f89SApple OSS Distributions struct os_refgrp *__debug_only grp,
546*f6217f89SApple OSS Distributions os_ref_count_t init_count, uint32_t init_bits)
547*f6217f89SApple OSS Distributions {
548*f6217f89SApple OSS Distributions assert(init_bits < (1U << b));
549*f6217f89SApple OSS Distributions atomic_init(rc, (init_count << b) | init_bits);
550*f6217f89SApple OSS Distributions os_ref_check_underflow(rc, (init_count << b), 1u << b);
551*f6217f89SApple OSS Distributions
552*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
553*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
554*f6217f89SApple OSS Distributions ref_init_debug(rc, grp, init_count);
555*f6217f89SApple OSS Distributions }
556*f6217f89SApple OSS Distributions #endif
557*f6217f89SApple OSS Distributions }
558*f6217f89SApple OSS Distributions
559*f6217f89SApple OSS Distributions __attribute__((always_inline))
560*f6217f89SApple OSS Distributions static inline void
os_ref_retain_mask_inline(os_ref_atomic_t * rc,uint32_t n,struct os_refgrp * __debug_only grp,memory_order mo)561*f6217f89SApple OSS Distributions os_ref_retain_mask_inline(os_ref_atomic_t *rc, uint32_t n,
562*f6217f89SApple OSS Distributions struct os_refgrp *__debug_only grp, memory_order mo)
563*f6217f89SApple OSS Distributions {
564*f6217f89SApple OSS Distributions os_ref_count_t old = atomic_fetch_add_explicit(rc, n, mo);
565*f6217f89SApple OSS Distributions os_ref_check_retain(rc, old, n);
566*f6217f89SApple OSS Distributions
567*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
568*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
569*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
570*f6217f89SApple OSS Distributions }
571*f6217f89SApple OSS Distributions #endif
572*f6217f89SApple OSS Distributions }
573*f6217f89SApple OSS Distributions
574*f6217f89SApple OSS Distributions void
os_ref_retain_mask_internal(os_ref_atomic_t * rc,uint32_t n,struct os_refgrp * __debug_only grp)575*f6217f89SApple OSS Distributions os_ref_retain_mask_internal(os_ref_atomic_t *rc, uint32_t n,
576*f6217f89SApple OSS Distributions struct os_refgrp *__debug_only grp)
577*f6217f89SApple OSS Distributions {
578*f6217f89SApple OSS Distributions os_ref_retain_mask_inline(rc, n, grp, memory_order_relaxed);
579*f6217f89SApple OSS Distributions }
580*f6217f89SApple OSS Distributions
581*f6217f89SApple OSS Distributions void
os_ref_retain_acquire_mask_internal(os_ref_atomic_t * rc,uint32_t n,struct os_refgrp * __debug_only grp)582*f6217f89SApple OSS Distributions os_ref_retain_acquire_mask_internal(os_ref_atomic_t *rc, uint32_t n,
583*f6217f89SApple OSS Distributions struct os_refgrp *__debug_only grp)
584*f6217f89SApple OSS Distributions {
585*f6217f89SApple OSS Distributions os_ref_retain_mask_inline(rc, n, grp, memory_order_acquire);
586*f6217f89SApple OSS Distributions }
587*f6217f89SApple OSS Distributions
588*f6217f89SApple OSS Distributions uint32_t
os_ref_release_barrier_mask_internal(os_ref_atomic_t * rc,uint32_t n,struct os_refgrp * __debug_only grp)589*f6217f89SApple OSS Distributions os_ref_release_barrier_mask_internal(os_ref_atomic_t *rc, uint32_t n,
590*f6217f89SApple OSS Distributions struct os_refgrp *__debug_only grp)
591*f6217f89SApple OSS Distributions {
592*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
593*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
594*f6217f89SApple OSS Distributions return os_ref_release_n_internal(rc, n, grp,
595*f6217f89SApple OSS Distributions memory_order_release, memory_order_acquire);
596*f6217f89SApple OSS Distributions }
597*f6217f89SApple OSS Distributions #endif
598*f6217f89SApple OSS Distributions
599*f6217f89SApple OSS Distributions return _os_ref_release_inline(rc, n, NULL,
600*f6217f89SApple OSS Distributions memory_order_release, memory_order_acquire);
601*f6217f89SApple OSS Distributions }
602*f6217f89SApple OSS Distributions
603*f6217f89SApple OSS Distributions uint32_t
os_ref_release_relaxed_mask_internal(os_ref_atomic_t * rc,uint32_t n,struct os_refgrp * __debug_only grp)604*f6217f89SApple OSS Distributions os_ref_release_relaxed_mask_internal(os_ref_atomic_t *rc, uint32_t n,
605*f6217f89SApple OSS Distributions struct os_refgrp *__debug_only grp)
606*f6217f89SApple OSS Distributions {
607*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
608*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
609*f6217f89SApple OSS Distributions return os_ref_release_n_internal(rc, n, grp,
610*f6217f89SApple OSS Distributions memory_order_relaxed, memory_order_relaxed);
611*f6217f89SApple OSS Distributions }
612*f6217f89SApple OSS Distributions #endif
613*f6217f89SApple OSS Distributions
614*f6217f89SApple OSS Distributions return _os_ref_release_inline(rc, n, NULL,
615*f6217f89SApple OSS Distributions memory_order_relaxed, memory_order_relaxed);
616*f6217f89SApple OSS Distributions }
617*f6217f89SApple OSS Distributions
618*f6217f89SApple OSS Distributions uint32_t
os_ref_retain_try_mask_internal(os_ref_atomic_t * rc,uint32_t n,uint32_t reject_mask,struct os_refgrp * __debug_only grp)619*f6217f89SApple OSS Distributions os_ref_retain_try_mask_internal(os_ref_atomic_t *rc, uint32_t n,
620*f6217f89SApple OSS Distributions uint32_t reject_mask, struct os_refgrp *__debug_only grp)
621*f6217f89SApple OSS Distributions {
622*f6217f89SApple OSS Distributions os_ref_count_t cur, next;
623*f6217f89SApple OSS Distributions
624*f6217f89SApple OSS Distributions os_atomic_rmw_loop(rc, cur, next, relaxed, {
625*f6217f89SApple OSS Distributions if (__improbable(cur < n || (cur & reject_mask))) {
626*f6217f89SApple OSS Distributions os_atomic_rmw_loop_give_up(return 0);
627*f6217f89SApple OSS Distributions }
628*f6217f89SApple OSS Distributions next = cur + n;
629*f6217f89SApple OSS Distributions });
630*f6217f89SApple OSS Distributions
631*f6217f89SApple OSS Distributions os_ref_check_overflow(rc, cur);
632*f6217f89SApple OSS Distributions
633*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
634*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
635*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
636*f6217f89SApple OSS Distributions }
637*f6217f89SApple OSS Distributions #endif
638*f6217f89SApple OSS Distributions
639*f6217f89SApple OSS Distributions return next;
640*f6217f89SApple OSS Distributions }
641*f6217f89SApple OSS Distributions
642*f6217f89SApple OSS Distributions bool
os_ref_retain_try_acquire_mask_internal(os_ref_atomic_t * rc,uint32_t n,uint32_t reject_mask,struct os_refgrp * __debug_only grp)643*f6217f89SApple OSS Distributions os_ref_retain_try_acquire_mask_internal(os_ref_atomic_t *rc, uint32_t n,
644*f6217f89SApple OSS Distributions uint32_t reject_mask, struct os_refgrp *__debug_only grp)
645*f6217f89SApple OSS Distributions {
646*f6217f89SApple OSS Distributions os_ref_count_t cur, next;
647*f6217f89SApple OSS Distributions
648*f6217f89SApple OSS Distributions os_atomic_rmw_loop(rc, cur, next, acquire, {
649*f6217f89SApple OSS Distributions if (__improbable(cur < n || (cur & reject_mask))) {
650*f6217f89SApple OSS Distributions os_atomic_rmw_loop_give_up(return false);
651*f6217f89SApple OSS Distributions }
652*f6217f89SApple OSS Distributions next = cur + n;
653*f6217f89SApple OSS Distributions });
654*f6217f89SApple OSS Distributions
655*f6217f89SApple OSS Distributions os_ref_check_overflow(rc, cur);
656*f6217f89SApple OSS Distributions
657*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
658*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
659*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
660*f6217f89SApple OSS Distributions }
661*f6217f89SApple OSS Distributions #endif
662*f6217f89SApple OSS Distributions
663*f6217f89SApple OSS Distributions return true;
664*f6217f89SApple OSS Distributions }
665*f6217f89SApple OSS Distributions
666*f6217f89SApple OSS Distributions #pragma mark os_pcpu
667*f6217f89SApple OSS Distributions
668*f6217f89SApple OSS Distributions #define OS_PCPU_REF_LIVE 1ull
669*f6217f89SApple OSS Distributions #define OS_PCPU_REF_WAITER 2ull
670*f6217f89SApple OSS Distributions #define OS_PCPU_REF_INC 4ull
671*f6217f89SApple OSS Distributions
672*f6217f89SApple OSS Distributions typedef uint64_t _Atomic *__zpercpu __os_pcpu_ref_t;
673*f6217f89SApple OSS Distributions
674*f6217f89SApple OSS Distributions static inline __os_pcpu_ref_t
os_pcpu_get(os_pcpu_ref_t ref)675*f6217f89SApple OSS Distributions os_pcpu_get(os_pcpu_ref_t ref)
676*f6217f89SApple OSS Distributions {
677*f6217f89SApple OSS Distributions return (__os_pcpu_ref_t)ref;
678*f6217f89SApple OSS Distributions }
679*f6217f89SApple OSS Distributions
680*f6217f89SApple OSS Distributions static inline uint64_t
os_pcpu_count_to_value(os_ref_count_t cnt)681*f6217f89SApple OSS Distributions os_pcpu_count_to_value(os_ref_count_t cnt)
682*f6217f89SApple OSS Distributions {
683*f6217f89SApple OSS Distributions return cnt * OS_PCPU_REF_INC;
684*f6217f89SApple OSS Distributions }
685*f6217f89SApple OSS Distributions
686*f6217f89SApple OSS Distributions static inline os_ref_count_t
os_pcpu_value_to_count(uint64_t v)687*f6217f89SApple OSS Distributions os_pcpu_value_to_count(uint64_t v)
688*f6217f89SApple OSS Distributions {
689*f6217f89SApple OSS Distributions return (os_ref_count_t)(v / OS_PCPU_REF_INC);
690*f6217f89SApple OSS Distributions }
691*f6217f89SApple OSS Distributions
692*f6217f89SApple OSS Distributions __abortlike
693*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_destroy_panic(os_pcpu_ref_t * ref,uint64_t n)694*f6217f89SApple OSS Distributions __os_pcpu_ref_destroy_panic(os_pcpu_ref_t *ref, uint64_t n)
695*f6217f89SApple OSS Distributions {
696*f6217f89SApple OSS Distributions if (n & OS_PCPU_REF_LIVE) {
697*f6217f89SApple OSS Distributions panic("os_pcpu_ref: destroying live refcount %p at %p",
698*f6217f89SApple OSS Distributions os_pcpu_get(*ref), ref);
699*f6217f89SApple OSS Distributions }
700*f6217f89SApple OSS Distributions if (n & OS_PCPU_REF_WAITER) {
701*f6217f89SApple OSS Distributions panic("os_pcpu_ref: destroying refcount %p with a waiter at %p",
702*f6217f89SApple OSS Distributions os_pcpu_get(*ref), ref);
703*f6217f89SApple OSS Distributions }
704*f6217f89SApple OSS Distributions panic("os_pcpu_ref: destroying non-zero refcount %p at %p",
705*f6217f89SApple OSS Distributions os_pcpu_get(*ref), ref);
706*f6217f89SApple OSS Distributions }
707*f6217f89SApple OSS Distributions
708*f6217f89SApple OSS Distributions __abortlike
709*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_overflow_panic(__os_pcpu_ref_t rc)710*f6217f89SApple OSS Distributions __os_pcpu_ref_overflow_panic(__os_pcpu_ref_t rc)
711*f6217f89SApple OSS Distributions {
712*f6217f89SApple OSS Distributions panic("os_pcpu_ref: overflow (rc=%p)", rc);
713*f6217f89SApple OSS Distributions }
714*f6217f89SApple OSS Distributions
715*f6217f89SApple OSS Distributions __abortlike
716*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_retain_panic(__os_pcpu_ref_t rc,uint64_t v)717*f6217f89SApple OSS Distributions __os_pcpu_ref_retain_panic(__os_pcpu_ref_t rc, uint64_t v)
718*f6217f89SApple OSS Distributions {
719*f6217f89SApple OSS Distributions if (v == 0) {
720*f6217f89SApple OSS Distributions panic("os_pcpu_ref: attempted resurrection (rc=%p)", rc);
721*f6217f89SApple OSS Distributions } else {
722*f6217f89SApple OSS Distributions __os_pcpu_ref_overflow_panic(rc);
723*f6217f89SApple OSS Distributions }
724*f6217f89SApple OSS Distributions }
725*f6217f89SApple OSS Distributions
726*f6217f89SApple OSS Distributions __abortlike
727*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_release_live_panic(__os_pcpu_ref_t rc)728*f6217f89SApple OSS Distributions __os_pcpu_ref_release_live_panic(__os_pcpu_ref_t rc)
729*f6217f89SApple OSS Distributions {
730*f6217f89SApple OSS Distributions panic("os_pcpu_ref: unexpected release of final reference (rc=%p)", rc);
731*f6217f89SApple OSS Distributions }
732*f6217f89SApple OSS Distributions
733*f6217f89SApple OSS Distributions __abortlike
734*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_release_panic(__os_pcpu_ref_t rc)735*f6217f89SApple OSS Distributions __os_pcpu_ref_release_panic(__os_pcpu_ref_t rc)
736*f6217f89SApple OSS Distributions {
737*f6217f89SApple OSS Distributions panic("os_pcpu_ref: over-release (rc=%p)", rc);
738*f6217f89SApple OSS Distributions }
739*f6217f89SApple OSS Distributions
740*f6217f89SApple OSS Distributions __abortlike
741*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_kill_panic(__os_pcpu_ref_t rc)742*f6217f89SApple OSS Distributions __os_pcpu_ref_kill_panic(__os_pcpu_ref_t rc)
743*f6217f89SApple OSS Distributions {
744*f6217f89SApple OSS Distributions panic("os_pcpu_ref: double-kill (rc=%p)", rc);
745*f6217f89SApple OSS Distributions }
746*f6217f89SApple OSS Distributions
747*f6217f89SApple OSS Distributions __abortlike
748*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_invalid_wait_panic(__os_pcpu_ref_t rc,uint64_t ov)749*f6217f89SApple OSS Distributions __os_pcpu_ref_invalid_wait_panic(__os_pcpu_ref_t rc, uint64_t ov)
750*f6217f89SApple OSS Distributions {
751*f6217f89SApple OSS Distributions if (ov & OS_PCPU_REF_WAITER) {
752*f6217f89SApple OSS Distributions panic("os_pcpu_ref: double-wait (rc=%p)", rc);
753*f6217f89SApple OSS Distributions } else {
754*f6217f89SApple OSS Distributions panic("os_pcpu_ref: wait while still live (rc=%p)", rc);
755*f6217f89SApple OSS Distributions }
756*f6217f89SApple OSS Distributions }
757*f6217f89SApple OSS Distributions
758*f6217f89SApple OSS Distributions void
759*f6217f89SApple OSS Distributions (os_pcpu_ref_init)(os_pcpu_ref_t * ref, struct os_refgrp *__debug_only grp)
760*f6217f89SApple OSS Distributions {
761*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc;
762*f6217f89SApple OSS Distributions
763*f6217f89SApple OSS Distributions rc = zalloc_percpu(percpu_u64_zone, Z_WAITOK | Z_NOFAIL);
zpercpu_foreach_cpu(cpu)764*f6217f89SApple OSS Distributions zpercpu_foreach_cpu(cpu) {
765*f6217f89SApple OSS Distributions os_atomic_init(zpercpu_get_cpu(rc, cpu),
766*f6217f89SApple OSS Distributions OS_PCPU_REF_LIVE + (cpu ? 0 : OS_PCPU_REF_INC));
767*f6217f89SApple OSS Distributions }
768*f6217f89SApple OSS Distributions
769*f6217f89SApple OSS Distributions *ref = (os_pcpu_ref_t)rc;
770*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
771*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
772*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
773*f6217f89SApple OSS Distributions }
774*f6217f89SApple OSS Distributions #endif
775*f6217f89SApple OSS Distributions }
776*f6217f89SApple OSS Distributions
777*f6217f89SApple OSS Distributions void
778*f6217f89SApple OSS Distributions (os_pcpu_ref_destroy)(os_pcpu_ref_t * ref, struct os_refgrp *__debug_only grp)
779*f6217f89SApple OSS Distributions {
780*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc = os_pcpu_get(*ref);
781*f6217f89SApple OSS Distributions uint64_t n = 0;
782*f6217f89SApple OSS Distributions
783*f6217f89SApple OSS Distributions n = os_atomic_load_wide(zpercpu_get_cpu(rc, 0), relaxed);
784*f6217f89SApple OSS Distributions if (n & OS_PCPU_REF_LIVE) {
785*f6217f89SApple OSS Distributions n = os_pcpu_ref_kill(*ref, grp);
786*f6217f89SApple OSS Distributions } else {
787*f6217f89SApple OSS Distributions for (int cpu = zpercpu_count(); cpu-- > 1;) {
788*f6217f89SApple OSS Distributions n |= os_atomic_load_wide(zpercpu_get_cpu(rc, cpu), relaxed);
789*f6217f89SApple OSS Distributions }
790*f6217f89SApple OSS Distributions }
791*f6217f89SApple OSS Distributions if (n) {
792*f6217f89SApple OSS Distributions __os_pcpu_ref_destroy_panic(ref, n);
793*f6217f89SApple OSS Distributions }
794*f6217f89SApple OSS Distributions
795*f6217f89SApple OSS Distributions *ref = 0;
796*f6217f89SApple OSS Distributions zfree_percpu(percpu_u64_zone, rc);
797*f6217f89SApple OSS Distributions }
798*f6217f89SApple OSS Distributions
799*f6217f89SApple OSS Distributions os_ref_count_t
os_pcpu_ref_count(os_pcpu_ref_t ref)800*f6217f89SApple OSS Distributions os_pcpu_ref_count(os_pcpu_ref_t ref)
801*f6217f89SApple OSS Distributions {
802*f6217f89SApple OSS Distributions uint64_t v;
803*f6217f89SApple OSS Distributions
804*f6217f89SApple OSS Distributions v = os_atomic_load_wide(zpercpu_get_cpu(os_pcpu_get(ref), 0), relaxed);
805*f6217f89SApple OSS Distributions if (v & OS_PCPU_REF_LIVE) {
806*f6217f89SApple OSS Distributions return OS_REFCNT_MAX_COUNT;
807*f6217f89SApple OSS Distributions }
808*f6217f89SApple OSS Distributions return os_pcpu_value_to_count(v);
809*f6217f89SApple OSS Distributions }
810*f6217f89SApple OSS Distributions
811*f6217f89SApple OSS Distributions static inline uint64_t
__os_pcpu_ref_delta(__os_pcpu_ref_t rc,int delta,int * cpup)812*f6217f89SApple OSS Distributions __os_pcpu_ref_delta(__os_pcpu_ref_t rc, int delta, int *cpup)
813*f6217f89SApple OSS Distributions {
814*f6217f89SApple OSS Distributions _Atomic uint64_t *rcp;
815*f6217f89SApple OSS Distributions uint64_t v;
816*f6217f89SApple OSS Distributions int cpu;
817*f6217f89SApple OSS Distributions
818*f6217f89SApple OSS Distributions cpu = cpu_number();
819*f6217f89SApple OSS Distributions rcp = zpercpu_get_cpu(rc, cpu);
820*f6217f89SApple OSS Distributions v = os_atomic_load_wide(rcp, relaxed);
821*f6217f89SApple OSS Distributions if (__improbable((v & OS_PCPU_REF_LIVE) == 0)) {
822*f6217f89SApple OSS Distributions *cpup = -1;
823*f6217f89SApple OSS Distributions return v;
824*f6217f89SApple OSS Distributions }
825*f6217f89SApple OSS Distributions
826*f6217f89SApple OSS Distributions *cpup = cpu;
827*f6217f89SApple OSS Distributions if (delta > 0) {
828*f6217f89SApple OSS Distributions return os_atomic_add_orig(rcp, OS_PCPU_REF_INC, relaxed);
829*f6217f89SApple OSS Distributions } else {
830*f6217f89SApple OSS Distributions return os_atomic_sub_orig(rcp, OS_PCPU_REF_INC, release);
831*f6217f89SApple OSS Distributions }
832*f6217f89SApple OSS Distributions }
833*f6217f89SApple OSS Distributions
834*f6217f89SApple OSS Distributions __attribute__((noinline))
835*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_retain_slow(__os_pcpu_ref_t rc,int cpu,uint64_t v)836*f6217f89SApple OSS Distributions __os_pcpu_ref_retain_slow(__os_pcpu_ref_t rc, int cpu, uint64_t v)
837*f6217f89SApple OSS Distributions {
838*f6217f89SApple OSS Distributions if (cpu > 0) {
839*f6217f89SApple OSS Distributions os_atomic_sub(zpercpu_get_cpu(rc, cpu),
840*f6217f89SApple OSS Distributions OS_PCPU_REF_INC, relaxed);
841*f6217f89SApple OSS Distributions }
842*f6217f89SApple OSS Distributions
843*f6217f89SApple OSS Distributions if (cpu != 0) {
844*f6217f89SApple OSS Distributions v = os_atomic_add_orig(zpercpu_get_cpu(rc, 0),
845*f6217f89SApple OSS Distributions OS_PCPU_REF_INC, relaxed);
846*f6217f89SApple OSS Distributions if (v & OS_PCPU_REF_LIVE) {
847*f6217f89SApple OSS Distributions /* we're doing this concurrently to an os_pcpu_ref_kill */
848*f6217f89SApple OSS Distributions return;
849*f6217f89SApple OSS Distributions }
850*f6217f89SApple OSS Distributions }
851*f6217f89SApple OSS Distributions
852*f6217f89SApple OSS Distributions if (v == 0 || v >= os_pcpu_count_to_value(OS_REFCNT_MAX_COUNT)) {
853*f6217f89SApple OSS Distributions __os_pcpu_ref_retain_panic(rc, v);
854*f6217f89SApple OSS Distributions }
855*f6217f89SApple OSS Distributions }
856*f6217f89SApple OSS Distributions
857*f6217f89SApple OSS Distributions void
858*f6217f89SApple OSS Distributions (os_pcpu_ref_retain)(os_pcpu_ref_t ref, struct os_refgrp * __debug_only grp)
859*f6217f89SApple OSS Distributions {
860*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc = os_pcpu_get(ref);
861*f6217f89SApple OSS Distributions uint64_t v;
862*f6217f89SApple OSS Distributions int cpu;
863*f6217f89SApple OSS Distributions
864*f6217f89SApple OSS Distributions v = __os_pcpu_ref_delta(rc, +1, &cpu);
865*f6217f89SApple OSS Distributions if (__improbable((v & OS_PCPU_REF_LIVE) == 0)) {
866*f6217f89SApple OSS Distributions __os_pcpu_ref_retain_slow(rc, cpu, v);
867*f6217f89SApple OSS Distributions }
868*f6217f89SApple OSS Distributions
869*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
870*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
871*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
872*f6217f89SApple OSS Distributions }
873*f6217f89SApple OSS Distributions #endif
874*f6217f89SApple OSS Distributions }
875*f6217f89SApple OSS Distributions
876*f6217f89SApple OSS Distributions bool
877*f6217f89SApple OSS Distributions (os_pcpu_ref_retain_try)(os_pcpu_ref_t ref, struct os_refgrp *__debug_only grp)
878*f6217f89SApple OSS Distributions {
879*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc = os_pcpu_get(ref);
880*f6217f89SApple OSS Distributions _Atomic uint64_t *rcp = zpercpu_get(rc);
881*f6217f89SApple OSS Distributions uint64_t ov, nv;
882*f6217f89SApple OSS Distributions
883*f6217f89SApple OSS Distributions os_atomic_rmw_loop(rcp, ov, nv, relaxed, {
884*f6217f89SApple OSS Distributions if ((ov & OS_PCPU_REF_LIVE) == 0) {
885*f6217f89SApple OSS Distributions os_atomic_rmw_loop_give_up(return false);
886*f6217f89SApple OSS Distributions }
887*f6217f89SApple OSS Distributions nv = ov + OS_PCPU_REF_INC;
888*f6217f89SApple OSS Distributions });
889*f6217f89SApple OSS Distributions
890*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
891*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
892*f6217f89SApple OSS Distributions ref_retain_debug(rc, grp);
893*f6217f89SApple OSS Distributions }
894*f6217f89SApple OSS Distributions #endif
895*f6217f89SApple OSS Distributions return true;
896*f6217f89SApple OSS Distributions }
897*f6217f89SApple OSS Distributions
898*f6217f89SApple OSS Distributions __attribute__((noinline))
899*f6217f89SApple OSS Distributions static void
__os_pcpu_ref_release_live_slow(__os_pcpu_ref_t rc,int cpu,uint64_t v)900*f6217f89SApple OSS Distributions __os_pcpu_ref_release_live_slow(__os_pcpu_ref_t rc, int cpu, uint64_t v)
901*f6217f89SApple OSS Distributions {
902*f6217f89SApple OSS Distributions if (cpu > 0) {
903*f6217f89SApple OSS Distributions os_atomic_add(zpercpu_get_cpu(rc, cpu),
904*f6217f89SApple OSS Distributions OS_PCPU_REF_INC, relaxed);
905*f6217f89SApple OSS Distributions }
906*f6217f89SApple OSS Distributions if (cpu != 0) {
907*f6217f89SApple OSS Distributions v = os_atomic_sub_orig(zpercpu_get_cpu(rc, 0),
908*f6217f89SApple OSS Distributions OS_PCPU_REF_INC, release);
909*f6217f89SApple OSS Distributions if (v & OS_PCPU_REF_LIVE) {
910*f6217f89SApple OSS Distributions /* we're doing this concurrently to an os_pcpu_ref_kill */
911*f6217f89SApple OSS Distributions return;
912*f6217f89SApple OSS Distributions }
913*f6217f89SApple OSS Distributions }
914*f6217f89SApple OSS Distributions
915*f6217f89SApple OSS Distributions if (v < os_pcpu_count_to_value(2)) {
916*f6217f89SApple OSS Distributions __os_pcpu_ref_release_live_panic(rc);
917*f6217f89SApple OSS Distributions }
918*f6217f89SApple OSS Distributions }
919*f6217f89SApple OSS Distributions
920*f6217f89SApple OSS Distributions void
921*f6217f89SApple OSS Distributions (os_pcpu_ref_release_live)(os_pcpu_ref_t ref, struct os_refgrp *__debug_only grp)
922*f6217f89SApple OSS Distributions {
923*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc = os_pcpu_get(ref);
924*f6217f89SApple OSS Distributions uint64_t v;
925*f6217f89SApple OSS Distributions int cpu;
926*f6217f89SApple OSS Distributions
927*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
928*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
929*f6217f89SApple OSS Distributions /*
930*f6217f89SApple OSS Distributions * Care not to use 'rc' after the decrement because it might be deallocated
931*f6217f89SApple OSS Distributions * under us.
932*f6217f89SApple OSS Distributions */
933*f6217f89SApple OSS Distributions ref_release_debug(rc, grp);
934*f6217f89SApple OSS Distributions }
935*f6217f89SApple OSS Distributions #endif
936*f6217f89SApple OSS Distributions
937*f6217f89SApple OSS Distributions v = __os_pcpu_ref_delta(rc, -1, &cpu);
938*f6217f89SApple OSS Distributions
939*f6217f89SApple OSS Distributions if (__improbable((v & OS_PCPU_REF_LIVE) == 0)) {
940*f6217f89SApple OSS Distributions __os_pcpu_ref_release_live_slow(rc, cpu, v);
941*f6217f89SApple OSS Distributions }
942*f6217f89SApple OSS Distributions }
943*f6217f89SApple OSS Distributions
944*f6217f89SApple OSS Distributions __attribute__((noinline))
945*f6217f89SApple OSS Distributions static os_ref_count_t
__os_pcpu_ref_release_slow(__os_pcpu_ref_t rc,int cpu,uint64_t v __os_refgrp_arg (struct os_refgrp * grp))946*f6217f89SApple OSS Distributions __os_pcpu_ref_release_slow(
947*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc,
948*f6217f89SApple OSS Distributions int cpu,
949*f6217f89SApple OSS Distributions uint64_t v
950*f6217f89SApple OSS Distributions __os_refgrp_arg(struct os_refgrp *grp))
951*f6217f89SApple OSS Distributions {
952*f6217f89SApple OSS Distributions uint64_t _Atomic *rc0 = zpercpu_get_cpu(rc, 0);
953*f6217f89SApple OSS Distributions
954*f6217f89SApple OSS Distributions if (cpu > 0) {
955*f6217f89SApple OSS Distributions os_atomic_add(zpercpu_get_cpu(rc, cpu),
956*f6217f89SApple OSS Distributions OS_PCPU_REF_INC, relaxed);
957*f6217f89SApple OSS Distributions }
958*f6217f89SApple OSS Distributions if (cpu != 0) {
959*f6217f89SApple OSS Distributions v = os_atomic_sub_orig(rc0, OS_PCPU_REF_INC, release);
960*f6217f89SApple OSS Distributions if (v & OS_PCPU_REF_LIVE) {
961*f6217f89SApple OSS Distributions /* we're doing this concurrently to an os_pcpu_ref_kill */
962*f6217f89SApple OSS Distributions return OS_REFCNT_MAX_COUNT;
963*f6217f89SApple OSS Distributions }
964*f6217f89SApple OSS Distributions }
965*f6217f89SApple OSS Distributions
966*f6217f89SApple OSS Distributions if (os_sub_overflow(v, OS_PCPU_REF_INC, &v)) {
967*f6217f89SApple OSS Distributions __os_pcpu_ref_release_panic(rc);
968*f6217f89SApple OSS Distributions }
969*f6217f89SApple OSS Distributions
970*f6217f89SApple OSS Distributions os_atomic_thread_fence(acquire);
971*f6217f89SApple OSS Distributions if (v == OS_PCPU_REF_WAITER) {
972*f6217f89SApple OSS Distributions os_atomic_andnot(rc0, OS_PCPU_REF_WAITER, release);
973*f6217f89SApple OSS Distributions thread_wakeup(rc);
974*f6217f89SApple OSS Distributions v = 0;
975*f6217f89SApple OSS Distributions }
976*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
977*f6217f89SApple OSS Distributions if (v == 0 && REFLOG_GRP_DEBUG_ENABLED(grp)) {
978*f6217f89SApple OSS Distributions return ref_drop_debug(rc, grp);
979*f6217f89SApple OSS Distributions }
980*f6217f89SApple OSS Distributions #endif
981*f6217f89SApple OSS Distributions return os_pcpu_value_to_count(v);
982*f6217f89SApple OSS Distributions }
983*f6217f89SApple OSS Distributions
os_ref_count_t(os_pcpu_ref_release)984*f6217f89SApple OSS Distributions os_ref_count_t
985*f6217f89SApple OSS Distributions (os_pcpu_ref_release)(os_pcpu_ref_t ref, struct os_refgrp *__debug_only grp)
986*f6217f89SApple OSS Distributions {
987*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc = os_pcpu_get(ref);
988*f6217f89SApple OSS Distributions uint64_t v;
989*f6217f89SApple OSS Distributions int cpu;
990*f6217f89SApple OSS Distributions
991*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
992*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
993*f6217f89SApple OSS Distributions ref_release_debug(rc, grp);
994*f6217f89SApple OSS Distributions }
995*f6217f89SApple OSS Distributions #endif
996*f6217f89SApple OSS Distributions
997*f6217f89SApple OSS Distributions v = __os_pcpu_ref_delta(rc, -1, &cpu);
998*f6217f89SApple OSS Distributions if (__improbable((v & OS_PCPU_REF_LIVE) == 0)) {
999*f6217f89SApple OSS Distributions return __os_pcpu_ref_release_slow(rc, cpu, v __os_refgrp_arg(grp));
1000*f6217f89SApple OSS Distributions }
1001*f6217f89SApple OSS Distributions
1002*f6217f89SApple OSS Distributions return OS_REFCNT_MAX_COUNT;
1003*f6217f89SApple OSS Distributions }
1004*f6217f89SApple OSS Distributions
os_ref_count_t(os_pcpu_ref_kill)1005*f6217f89SApple OSS Distributions os_ref_count_t
1006*f6217f89SApple OSS Distributions (os_pcpu_ref_kill)(os_pcpu_ref_t ref, struct os_refgrp *__debug_only grp)
1007*f6217f89SApple OSS Distributions {
1008*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc = os_pcpu_get(ref);
1009*f6217f89SApple OSS Distributions uint64_t v = 0, t = 0;
1010*f6217f89SApple OSS Distributions
1011*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
1012*f6217f89SApple OSS Distributions if (REFLOG_GRP_DEBUG_ENABLED(grp)) {
1013*f6217f89SApple OSS Distributions ref_release_debug(rc, grp);
1014*f6217f89SApple OSS Distributions }
1015*f6217f89SApple OSS Distributions #endif
1016*f6217f89SApple OSS Distributions
1017*f6217f89SApple OSS Distributions for (int cpu = zpercpu_count(); cpu-- > 1;) {
1018*f6217f89SApple OSS Distributions v = os_atomic_xchg(zpercpu_get_cpu(rc, cpu), 0, relaxed);
1019*f6217f89SApple OSS Distributions if ((v & OS_PCPU_REF_LIVE) == 0) {
1020*f6217f89SApple OSS Distributions __os_pcpu_ref_kill_panic(rc);
1021*f6217f89SApple OSS Distributions }
1022*f6217f89SApple OSS Distributions t += v - OS_PCPU_REF_LIVE;
1023*f6217f89SApple OSS Distributions }
1024*f6217f89SApple OSS Distributions t -= OS_PCPU_REF_LIVE + OS_PCPU_REF_INC;
1025*f6217f89SApple OSS Distributions
1026*f6217f89SApple OSS Distributions v = os_atomic_add(zpercpu_get_cpu(rc, 0), t, acq_rel);
1027*f6217f89SApple OSS Distributions if (v & OS_PCPU_REF_LIVE) {
1028*f6217f89SApple OSS Distributions __os_pcpu_ref_kill_panic(rc);
1029*f6217f89SApple OSS Distributions }
1030*f6217f89SApple OSS Distributions
1031*f6217f89SApple OSS Distributions if (v >= os_pcpu_count_to_value(OS_REFCNT_MAX_COUNT)) {
1032*f6217f89SApple OSS Distributions __os_pcpu_ref_overflow_panic(rc);
1033*f6217f89SApple OSS Distributions }
1034*f6217f89SApple OSS Distributions
1035*f6217f89SApple OSS Distributions #if OS_REFCNT_DEBUG
1036*f6217f89SApple OSS Distributions if (v == 0 && REFLOG_GRP_DEBUG_ENABLED(grp)) {
1037*f6217f89SApple OSS Distributions return ref_drop_debug(rc, grp);
1038*f6217f89SApple OSS Distributions }
1039*f6217f89SApple OSS Distributions #endif
1040*f6217f89SApple OSS Distributions return os_pcpu_value_to_count(v);
1041*f6217f89SApple OSS Distributions }
1042*f6217f89SApple OSS Distributions
1043*f6217f89SApple OSS Distributions #if KERNEL
1044*f6217f89SApple OSS Distributions
1045*f6217f89SApple OSS Distributions void
os_pcpu_ref_wait_for_death(os_pcpu_ref_t ref)1046*f6217f89SApple OSS Distributions os_pcpu_ref_wait_for_death(os_pcpu_ref_t ref)
1047*f6217f89SApple OSS Distributions {
1048*f6217f89SApple OSS Distributions __os_pcpu_ref_t rc = os_pcpu_get(ref);
1049*f6217f89SApple OSS Distributions uint64_t _Atomic *rc0 = zpercpu_get_cpu(rc, 0);
1050*f6217f89SApple OSS Distributions uint64_t ov, nv;
1051*f6217f89SApple OSS Distributions
1052*f6217f89SApple OSS Distributions ov = os_atomic_load(rc0, relaxed);
1053*f6217f89SApple OSS Distributions if (ov == 0) {
1054*f6217f89SApple OSS Distributions os_atomic_thread_fence(acquire);
1055*f6217f89SApple OSS Distributions return;
1056*f6217f89SApple OSS Distributions }
1057*f6217f89SApple OSS Distributions
1058*f6217f89SApple OSS Distributions assert_wait(rc, THREAD_UNINT);
1059*f6217f89SApple OSS Distributions
1060*f6217f89SApple OSS Distributions os_atomic_rmw_loop(rc0, ov, nv, relaxed, {
1061*f6217f89SApple OSS Distributions if (ov & (OS_PCPU_REF_WAITER | OS_PCPU_REF_LIVE)) {
1062*f6217f89SApple OSS Distributions __os_pcpu_ref_invalid_wait_panic(rc, ov);
1063*f6217f89SApple OSS Distributions }
1064*f6217f89SApple OSS Distributions if (ov == 0) {
1065*f6217f89SApple OSS Distributions os_atomic_rmw_loop_give_up(break);
1066*f6217f89SApple OSS Distributions }
1067*f6217f89SApple OSS Distributions nv = ov | OS_PCPU_REF_WAITER;
1068*f6217f89SApple OSS Distributions });
1069*f6217f89SApple OSS Distributions
1070*f6217f89SApple OSS Distributions if (ov == 0) {
1071*f6217f89SApple OSS Distributions os_atomic_thread_fence(acquire);
1072*f6217f89SApple OSS Distributions clear_wait(current_thread(), THREAD_AWAKENED);
1073*f6217f89SApple OSS Distributions } else {
1074*f6217f89SApple OSS Distributions thread_block(THREAD_CONTINUE_NULL);
1075*f6217f89SApple OSS Distributions }
1076*f6217f89SApple OSS Distributions }
1077*f6217f89SApple OSS Distributions
1078*f6217f89SApple OSS Distributions #endif
1079