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