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