xref: /xnu-12377.1.9/libkern/os/refcnt.h (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
1*f6217f89SApple OSS Distributions /*
2*f6217f89SApple OSS Distributions  * Copyright (c) 2017 Apple Inc. All rights reserved.
3*f6217f89SApple OSS Distributions  *
4*f6217f89SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*f6217f89SApple OSS Distributions  *
6*f6217f89SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*f6217f89SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*f6217f89SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*f6217f89SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*f6217f89SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*f6217f89SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*f6217f89SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*f6217f89SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*f6217f89SApple OSS Distributions  *
15*f6217f89SApple OSS Distributions  * Please obtain a copy of the License at
16*f6217f89SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*f6217f89SApple OSS Distributions  *
18*f6217f89SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*f6217f89SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*f6217f89SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*f6217f89SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*f6217f89SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*f6217f89SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*f6217f89SApple OSS Distributions  * limitations under the License.
25*f6217f89SApple OSS Distributions  *
26*f6217f89SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*f6217f89SApple OSS Distributions  */
28*f6217f89SApple OSS Distributions 
29*f6217f89SApple OSS Distributions #ifndef _OS_REFCNT_H_
30*f6217f89SApple OSS Distributions #define _OS_REFCNT_H_
31*f6217f89SApple OSS Distributions 
32*f6217f89SApple OSS Distributions /*
33*f6217f89SApple OSS Distributions  * os_refcnt reference counting API
34*f6217f89SApple OSS Distributions  *
35*f6217f89SApple OSS Distributions  * Two flavors are provided: atomic and locked. Atomic internally uses C11 atomic
36*f6217f89SApple OSS Distributions  * operations and requires no external synchronization, whereas the locked flavor
37*f6217f89SApple OSS Distributions  * assumes the refcnt object is locked by the caller. It is NOT safe to
38*f6217f89SApple OSS Distributions  * mix-and-match locked and atomic calls.
39*f6217f89SApple OSS Distributions  *
40*f6217f89SApple OSS Distributions  * 'refgrp's are a way to (hierarchically) group like refcount objects for
41*f6217f89SApple OSS Distributions  * debugging purposes. The group keeps track of the total number and aggregate
42*f6217f89SApple OSS Distributions  * reference count of member refcounts, and the "rlog=" boot-arg is used to enable
43*f6217f89SApple OSS Distributions  * refcount logging by group name. Named groups can be created explicitly with
44*f6217f89SApple OSS Distributions  * os_refgrp_decl(), or implicitly by passing NULL for the refgrp when
45*f6217f89SApple OSS Distributions  * initializing a refcnt object. In the latter case, the group name is the same as
46*f6217f89SApple OSS Distributions  * the function enclosing the init call. Groups are only available on DEV or DEBUG
47*f6217f89SApple OSS Distributions  * builds, and are otherwise compiled out.
48*f6217f89SApple OSS Distributions  */
49*f6217f89SApple OSS Distributions 
50*f6217f89SApple OSS Distributions #include <stdatomic.h>
51*f6217f89SApple OSS Distributions #include <stdbool.h>
52*f6217f89SApple OSS Distributions #include <stdint.h>
53*f6217f89SApple OSS Distributions #include <os/base.h>
54*f6217f89SApple OSS Distributions 
55*f6217f89SApple OSS Distributions struct os_refcnt;
56*f6217f89SApple OSS Distributions struct os_refgrp;
57*f6217f89SApple OSS Distributions typedef struct os_refcnt os_refcnt_t;
58*f6217f89SApple OSS Distributions 
59*f6217f89SApple OSS Distributions /* type of the internal counter */
60*f6217f89SApple OSS Distributions typedef uint32_t os_ref_count_t;
61*f6217f89SApple OSS Distributions typedef _Atomic(os_ref_count_t) os_ref_atomic_t;
62*f6217f89SApple OSS Distributions 
63*f6217f89SApple OSS Distributions /*
64*f6217f89SApple OSS Distributions  * OS_REF_INITIALIZER
65*f6217f89SApple OSS Distributions  * OS_REF_ATOMIC_INITIALIZER
66*f6217f89SApple OSS Distributions  *
67*f6217f89SApple OSS Distributions  * Static initializers that create refcnt objects with safe initial values for use
68*f6217f89SApple OSS Distributions  * between declaration and initialization (os_ref*_init()). Equivalent to zeroing.
69*f6217f89SApple OSS Distributions  */
70*f6217f89SApple OSS Distributions 
71*f6217f89SApple OSS Distributions #ifndef KERNEL
72*f6217f89SApple OSS Distributions # include <stdlib.h>
73*f6217f89SApple OSS Distributions # include <stdio.h>
74*f6217f89SApple OSS Distributions # ifndef __improbable
75*f6217f89SApple OSS Distributions #  define __improbable(x) x
76*f6217f89SApple OSS Distributions # endif
77*f6217f89SApple OSS Distributions # ifndef panic
78*f6217f89SApple OSS Distributions #  define panic(x, ...) do { fprintf(stderr, x, __VA_ARGS__); abort(); } while (0)
79*f6217f89SApple OSS Distributions # endif
80*f6217f89SApple OSS Distributions #endif
81*f6217f89SApple OSS Distributions 
82*f6217f89SApple OSS Distributions #ifndef OS_REFCNT_DEBUG
83*f6217f89SApple OSS Distributions # if DEVELOPMENT || DEBUG
84*f6217f89SApple OSS Distributions #  define OS_REFCNT_DEBUG 1
85*f6217f89SApple OSS Distributions # else
86*f6217f89SApple OSS Distributions #  define OS_REFCNT_DEBUG 0
87*f6217f89SApple OSS Distributions # endif
88*f6217f89SApple OSS Distributions #endif
89*f6217f89SApple OSS Distributions 
90*f6217f89SApple OSS Distributions #if __has_attribute(diagnose_if)
91*f6217f89SApple OSS Distributions # define os_error_if(cond, msg) __attribute__((diagnose_if((cond), (msg), "error")))
92*f6217f89SApple OSS Distributions #else
93*f6217f89SApple OSS Distributions # define os_error_if(...)
94*f6217f89SApple OSS Distributions #endif
95*f6217f89SApple OSS Distributions 
96*f6217f89SApple OSS Distributions __BEGIN_DECLS
97*f6217f89SApple OSS Distributions 
98*f6217f89SApple OSS Distributions /*
99*f6217f89SApple OSS Distributions  * os_ref_init: initialize an os_refcnt with a count of 1
100*f6217f89SApple OSS Distributions  * os_ref_init_count: initialize an os_refcnt with a specific count >= 1
101*f6217f89SApple OSS Distributions  */
102*f6217f89SApple OSS Distributions #define os_ref_init(rc, grp) os_ref_init_count((rc), (grp), 1)
103*f6217f89SApple OSS Distributions static void os_ref_init_count(struct os_refcnt *, struct os_refgrp *, os_ref_count_t count)
104*f6217f89SApple OSS Distributions os_error_if(count == 0, "Reference count must be non-zero initialized");
105*f6217f89SApple OSS Distributions 
106*f6217f89SApple OSS Distributions /*
107*f6217f89SApple OSS Distributions  * os_refgrp_decl(qual, var, name, parent): declare a refgroup object 'var' with
108*f6217f89SApple OSS Distributions  *   given name string and parent group.
109*f6217f89SApple OSS Distributions  */
110*f6217f89SApple OSS Distributions 
111*f6217f89SApple OSS Distributions /*
112*f6217f89SApple OSS Distributions  *
113*f6217f89SApple OSS Distributions  * os_ref_retain: acquire a reference (increment reference count by 1) atomically.
114*f6217f89SApple OSS Distributions  *
115*f6217f89SApple OSS Distributions  * os_ref_release: release a reference (decrement reference count) atomically and
116*f6217f89SApple OSS Distributions  *		return the new count. Memory is synchronized such that the dealloc block
117*f6217f89SApple OSS Distributions  *		(i.e. code handling the final release() == 0 call) sees up-to-date memory
118*f6217f89SApple OSS Distributions  *		with respect to all prior release()s on the same refcnt object. This
119*f6217f89SApple OSS Distributions  *		memory ordering is sufficient for most use cases.
120*f6217f89SApple OSS Distributions  *
121*f6217f89SApple OSS Distributions  * os_ref_release_relaxed: same as release() but with weaker relaxed memory ordering.
122*f6217f89SApple OSS Distributions  *		This can be used when the dealloc block is already synchronized with other
123*f6217f89SApple OSS Distributions  *		accesses to the object (for example, with a lock).
124*f6217f89SApple OSS Distributions  *
125*f6217f89SApple OSS Distributions  * os_ref_release_live: release a reference that is guaranteed not to be the last one.
126*f6217f89SApple OSS Distributions  */
127*f6217f89SApple OSS Distributions static void os_ref_retain(struct os_refcnt *);
128*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_release(struct os_refcnt *) OS_WARN_RESULT;
129*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_release_relaxed(struct os_refcnt *) OS_WARN_RESULT;
130*f6217f89SApple OSS Distributions static void os_ref_release_live(struct os_refcnt *);
131*f6217f89SApple OSS Distributions 
132*f6217f89SApple OSS Distributions /*
133*f6217f89SApple OSS Distributions  * os_ref_retain_try: a variant of atomic retain that fails for objects with a
134*f6217f89SApple OSS Distributions  *		zero reference count. The caller must therefore ensure that the object
135*f6217f89SApple OSS Distributions  *		remains alive for any possible retain_try() caller, usually by using a
136*f6217f89SApple OSS Distributions  *		lock protecting both the retain and dealloc paths. This variant is useful
137*f6217f89SApple OSS Distributions  *		for objects stored in a collection, because no lock is required on the
138*f6217f89SApple OSS Distributions  *		release() side until the object is deallocated.
139*f6217f89SApple OSS Distributions  */
140*f6217f89SApple OSS Distributions static bool os_ref_retain_try(struct os_refcnt *) OS_WARN_RESULT;
141*f6217f89SApple OSS Distributions 
142*f6217f89SApple OSS Distributions /*
143*f6217f89SApple OSS Distributions  * os_ref_retain_locked: acquire a reference on an object protected by a held
144*f6217f89SApple OSS Distributions  *		lock. The caller must ensure mutual exclusivity of retain_locked() and
145*f6217f89SApple OSS Distributions  *		release_locked() calls on the same object.
146*f6217f89SApple OSS Distributions  *
147*f6217f89SApple OSS Distributions  * os_ref_release_locked: release a reference on an object protected by a held
148*f6217f89SApple OSS Distributions  *		lock.
149*f6217f89SApple OSS Distributions  */
150*f6217f89SApple OSS Distributions static void os_ref_retain_locked(struct os_refcnt *);
151*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_release_locked(struct os_refcnt *) OS_WARN_RESULT;
152*f6217f89SApple OSS Distributions 
153*f6217f89SApple OSS Distributions /*
154*f6217f89SApple OSS Distributions  * os_ref_get_count: return the current reference count. This is unsafe for
155*f6217f89SApple OSS Distributions  *		synchronization.
156*f6217f89SApple OSS Distributions  */
157*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_get_count(struct os_refcnt *rc);
158*f6217f89SApple OSS Distributions 
159*f6217f89SApple OSS Distributions 
160*f6217f89SApple OSS Distributions /*!
161*f6217f89SApple OSS Distributions  * @brief
162*f6217f89SApple OSS Distributions  * Type for scalable percpu refcounts.
163*f6217f89SApple OSS Distributions  *
164*f6217f89SApple OSS Distributions  * @discussion
165*f6217f89SApple OSS Distributions  * percpu refcounts are scalable refcounts that do not contend on retain/release
166*f6217f89SApple OSS Distributions  * but require O(ncpu) storage.
167*f6217f89SApple OSS Distributions  *
168*f6217f89SApple OSS Distributions  * They also require to be explicitly "killed" with @c os_pcpu_ref_kill() before
169*f6217f89SApple OSS Distributions  * the "last reference" detection logic kicks in, in which case the refcount
170*f6217f89SApple OSS Distributions  * decays to a regular (contending) atomic refcount.
171*f6217f89SApple OSS Distributions  *
172*f6217f89SApple OSS Distributions  * This type of refcount is typically useful for objects that are in low
173*f6217f89SApple OSS Distributions  * numbers, but are accessed frequently and must be protected against deletion,
174*f6217f89SApple OSS Distributions  * when options like SMR critical sections can't be used.
175*f6217f89SApple OSS Distributions  */
176*f6217f89SApple OSS Distributions typedef uintptr_t os_pcpu_ref_t;
177*f6217f89SApple OSS Distributions 
178*f6217f89SApple OSS Distributions /*!
179*f6217f89SApple OSS Distributions  * @brief
180*f6217f89SApple OSS Distributions  * Initializes a scalable refcount.
181*f6217f89SApple OSS Distributions  *
182*f6217f89SApple OSS Distributions  * @discussion
183*f6217f89SApple OSS Distributions  * The refcount is initialized with the value "1" and marked "live".
184*f6217f89SApple OSS Distributions  *
185*f6217f89SApple OSS Distributions  * This reference is supposed to be dropped with @c os_pcpu_ref_kill(),
186*f6217f89SApple OSS Distributions  * which will mark it as "dead", which is required for os_pcpu_ref_release()
187*f6217f89SApple OSS Distributions  * to become precise.
188*f6217f89SApple OSS Distributions  *
189*f6217f89SApple OSS Distributions  * The refcount must be destroyed with @c os_pcpu_ref_destroy() once
190*f6217f89SApple OSS Distributions  * @c os_pcpu_ref_release() returns 0.
191*f6217f89SApple OSS Distributions  */
192*f6217f89SApple OSS Distributions extern void os_pcpu_ref_init(os_pcpu_ref_t *ref, struct os_refgrp *grp);
193*f6217f89SApple OSS Distributions 
194*f6217f89SApple OSS Distributions /*!
195*f6217f89SApple OSS Distributions  * @brief
196*f6217f89SApple OSS Distributions  * "Kill" the initial reference of a percpu refcount.
197*f6217f89SApple OSS Distributions  *
198*f6217f89SApple OSS Distributions  * @discussion
199*f6217f89SApple OSS Distributions  * This drops the "creation" reference of the refcount made by
200*f6217f89SApple OSS Distributions  * @c os_pcpu_ref_init().
201*f6217f89SApple OSS Distributions  *
202*f6217f89SApple OSS Distributions  * Once a percpu refcount is "killed" it becomes a regular atomic refcount
203*f6217f89SApple OSS Distributions  * in order to do precise detection of the last reference drop.
204*f6217f89SApple OSS Distributions  *
205*f6217f89SApple OSS Distributions  * This returns the resulting refcount value, like @c os_pcpu_ref_release() does.
206*f6217f89SApple OSS Distributions  */
207*f6217f89SApple OSS Distributions extern os_ref_count_t os_pcpu_ref_kill(os_pcpu_ref_t ref, struct os_refgrp *grp) __result_use_check;
208*f6217f89SApple OSS Distributions 
209*f6217f89SApple OSS Distributions /*!
210*f6217f89SApple OSS Distributions  * @brief
211*f6217f89SApple OSS Distributions  * Wait for a killed refcount to hit 0.
212*f6217f89SApple OSS Distributions  *
213*f6217f89SApple OSS Distributions  * @discussion
214*f6217f89SApple OSS Distributions  * Waiting for object death must happen after the refcount has been "killed".
215*f6217f89SApple OSS Distributions  *
216*f6217f89SApple OSS Distributions  * There can only be at most a single waiter, given that it is expected that
217*f6217f89SApple OSS Distributions  * waiter will free resources, and having two waiters would cause use-after-free
218*f6217f89SApple OSS Distributions  * accesses.
219*f6217f89SApple OSS Distributions  *
220*f6217f89SApple OSS Distributions  * Having two waiters, or waiting on a live refcount will result into
221*f6217f89SApple OSS Distributions  * a kernel panic.
222*f6217f89SApple OSS Distributions  */
223*f6217f89SApple OSS Distributions extern void os_pcpu_ref_wait_for_death(os_pcpu_ref_t ref);
224*f6217f89SApple OSS Distributions 
225*f6217f89SApple OSS Distributions /*!
226*f6217f89SApple OSS Distributions  * @brief
227*f6217f89SApple OSS Distributions  * Destroy a scalable refcount once it has been killed and reached 0.
228*f6217f89SApple OSS Distributions  *
229*f6217f89SApple OSS Distributions  * @discussion
230*f6217f89SApple OSS Distributions  * This must be called to destroy a scalable refcount.
231*f6217f89SApple OSS Distributions  *
232*f6217f89SApple OSS Distributions  * It is legal to release a scalable refcount when:
233*f6217f89SApple OSS Distributions  * - @c os_pcpu_ref_kill() was called and returned 0;
234*f6217f89SApple OSS Distributions  * - @c os_pcpu_ref_kill() was called and @c os_pcpu_ref_release() returned 0;
235*f6217f89SApple OSS Distributions  * - the refcount was initialized with @c os_pcpu_ref_init() and never used nor
236*f6217f89SApple OSS Distributions  *   killed.
237*f6217f89SApple OSS Distributions  */
238*f6217f89SApple OSS Distributions extern void os_pcpu_ref_destroy(os_pcpu_ref_t *ref, struct os_refgrp *grp);
239*f6217f89SApple OSS Distributions 
240*f6217f89SApple OSS Distributions /*!
241*f6217f89SApple OSS Distributions  * @brief
242*f6217f89SApple OSS Distributions  * Returns the value of the refcount.
243*f6217f89SApple OSS Distributions  *
244*f6217f89SApple OSS Distributions  * @discussion
245*f6217f89SApple OSS Distributions  * If the refcount is still live (hasn't been killed yet),
246*f6217f89SApple OSS Distributions  * then this function returns a "very large" value.
247*f6217f89SApple OSS Distributions  */
248*f6217f89SApple OSS Distributions extern os_ref_count_t os_pcpu_ref_count(os_pcpu_ref_t ref);
249*f6217f89SApple OSS Distributions 
250*f6217f89SApple OSS Distributions /*!
251*f6217f89SApple OSS Distributions  * @brief
252*f6217f89SApple OSS Distributions  * Acquires a +1 reference on the specified percpu refcount.
253*f6217f89SApple OSS Distributions  */
254*f6217f89SApple OSS Distributions extern void os_pcpu_ref_retain(os_pcpu_ref_t ref, struct os_refgrp *grp);
255*f6217f89SApple OSS Distributions 
256*f6217f89SApple OSS Distributions /*!
257*f6217f89SApple OSS Distributions  * @brief
258*f6217f89SApple OSS Distributions  * Tries to acquire a +1 reference on the specified percpu refcount.
259*f6217f89SApple OSS Distributions  *
260*f6217f89SApple OSS Distributions  * @discussion
261*f6217f89SApple OSS Distributions  * Unlike a typical refcount, this function will fail as soon as
262*f6217f89SApple OSS Distributions  * @c os_pcpu_ref_kill() has been called, rather than because
263*f6217f89SApple OSS Distributions  * the refcount hit 0.
264*f6217f89SApple OSS Distributions  */
265*f6217f89SApple OSS Distributions extern bool os_pcpu_ref_retain_try(os_pcpu_ref_t ref, struct os_refgrp *grp) __result_use_check;
266*f6217f89SApple OSS Distributions 
267*f6217f89SApple OSS Distributions /*!
268*f6217f89SApple OSS Distributions  * @brief
269*f6217f89SApple OSS Distributions  * Release an acquired reference, knowing it is not the last one.
270*f6217f89SApple OSS Distributions  */
271*f6217f89SApple OSS Distributions extern void os_pcpu_ref_release_live(os_pcpu_ref_t ref, struct os_refgrp *grp);
272*f6217f89SApple OSS Distributions 
273*f6217f89SApple OSS Distributions /*!
274*f6217f89SApple OSS Distributions  * @brief
275*f6217f89SApple OSS Distributions  * Release an acquired reference.
276*f6217f89SApple OSS Distributions  *
277*f6217f89SApple OSS Distributions  * @discussion
278*f6217f89SApple OSS Distributions  * If the refcount is "live" the returned value will be a "very large number"
279*f6217f89SApple OSS Distributions  * that isn't really accurate.
280*f6217f89SApple OSS Distributions  *
281*f6217f89SApple OSS Distributions  * Once the refcount has been "killed" then this returns an accurate view of the
282*f6217f89SApple OSS Distributions  * refcount.
283*f6217f89SApple OSS Distributions  */
284*f6217f89SApple OSS Distributions extern os_ref_count_t os_pcpu_ref_release(os_pcpu_ref_t ref, struct os_refgrp *grp) __result_use_check;
285*f6217f89SApple OSS Distributions 
286*f6217f89SApple OSS Distributions 
287*f6217f89SApple OSS Distributions #if XNU_KERNEL_PRIVATE
288*f6217f89SApple OSS Distributions #pragma GCC visibility push(hidden)
289*f6217f89SApple OSS Distributions 
290*f6217f89SApple OSS Distributions /*
291*f6217f89SApple OSS Distributions  * Raw API that uses a plain atomic counter (os_ref_atomic_t) and a separate
292*f6217f89SApple OSS Distributions  * refgroup. This can be used in situations where the refcount object must be
293*f6217f89SApple OSS Distributions  * fixed size, for example for embedding in structures with ABI stability
294*f6217f89SApple OSS Distributions  * requirements.
295*f6217f89SApple OSS Distributions  */
296*f6217f89SApple OSS Distributions 
297*f6217f89SApple OSS Distributions #define os_ref_init_raw(rc, grp) os_ref_init_count_raw((rc), (grp), 1)
298*f6217f89SApple OSS Distributions static void os_ref_init_count_raw(os_ref_atomic_t *, struct os_refgrp *, os_ref_count_t count)
299*f6217f89SApple OSS Distributions os_error_if(count == 0, "Reference count must be non-zero initialized");
300*f6217f89SApple OSS Distributions static void os_ref_retain_floor(struct os_refcnt *, os_ref_count_t f)
301*f6217f89SApple OSS Distributions os_error_if(!__builtin_constant_p(f) || f == 0, "refcount floor must be >= 1");
302*f6217f89SApple OSS Distributions static void os_ref_retain_raw(os_ref_atomic_t *, struct os_refgrp *);
303*f6217f89SApple OSS Distributions static void os_ref_retain_floor_raw(os_ref_atomic_t *, os_ref_count_t f, struct os_refgrp *)
304*f6217f89SApple OSS Distributions os_error_if(!__builtin_constant_p(f) || f == 0, "refcount floor must be >= 1");
305*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_release_raw(os_ref_atomic_t *, struct os_refgrp *) OS_WARN_RESULT;
306*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_release_raw_relaxed(os_ref_atomic_t *, struct os_refgrp *) OS_WARN_RESULT;
307*f6217f89SApple OSS Distributions static void os_ref_release_live_raw(os_ref_atomic_t *, struct os_refgrp *);
308*f6217f89SApple OSS Distributions static bool os_ref_retain_try_raw(os_ref_atomic_t *, struct os_refgrp *) OS_WARN_RESULT;
309*f6217f89SApple OSS Distributions static bool os_ref_retain_floor_try_raw(os_ref_atomic_t *, os_ref_count_t f, struct os_refgrp *) OS_WARN_RESULT
310*f6217f89SApple OSS Distributions     os_error_if(!__builtin_constant_p(f) || f == 0, "refcount floor must be >= 1");
311*f6217f89SApple OSS Distributions static void os_ref_retain_locked_raw(os_ref_atomic_t *, struct os_refgrp *);
312*f6217f89SApple OSS Distributions static void os_ref_retain_floor_locked_raw(os_ref_atomic_t *, os_ref_count_t f, struct os_refgrp *)
313*f6217f89SApple OSS Distributions os_error_if(!__builtin_constant_p(f) || f == 0, "refcount floor must be >= 1");
314*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_release_locked_raw(os_ref_atomic_t *, struct os_refgrp *) OS_WARN_RESULT;
315*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_get_count_raw(os_ref_atomic_t *rc);
316*f6217f89SApple OSS Distributions 
317*f6217f89SApple OSS Distributions 
318*f6217f89SApple OSS Distributions /*
319*f6217f89SApple OSS Distributions  * Bitwise API: like the raw API, but allows some bits in the refcount value to be
320*f6217f89SApple OSS Distributions  * reserved for other purposes. 'b' defines the number of trailing (LSB) reserved
321*f6217f89SApple OSS Distributions  * bits, which the refcnt_raw API will never modify (except at init()).
322*f6217f89SApple OSS Distributions  *
323*f6217f89SApple OSS Distributions  * It is assumed that users of this API always use atomic ops on the
324*f6217f89SApple OSS Distributions  * os_ref_atomic_t (or hold a lock for the locked variants), and never modify the
325*f6217f89SApple OSS Distributions  * top (32 - 'b') bits.
326*f6217f89SApple OSS Distributions  *
327*f6217f89SApple OSS Distributions  * Due to guard bits, the maximum reference count is 2^(28 - 'b') - 1, and the
328*f6217f89SApple OSS Distributions  * maximum 'b' is 26 bits. This API can also be used just to limit the max
329*f6217f89SApple OSS Distributions  * refcount.
330*f6217f89SApple OSS Distributions  *
331*f6217f89SApple OSS Distributions  * The "*_raw_mask" APIs return the raw bit pattern of the refcount (with a type
332*f6217f89SApple OSS Distributions  * of uint32_t), that the caller is supposed to decode. Other APIs that return
333*f6217f89SApple OSS Distributions  * os_ref_count_t return a normalized refcount where the trailing bits have been
334*f6217f89SApple OSS Distributions  * removed.
335*f6217f89SApple OSS Distributions  *
336*f6217f89SApple OSS Distributions  * "locked" variants aren't provided as the point of these interfaces
337*f6217f89SApple OSS Distributions  * is to combine flags into a refcount and be able to manipulate both
338*f6217f89SApple OSS Distributions  * atomically with respect to each other.
339*f6217f89SApple OSS Distributions  */
340*f6217f89SApple OSS Distributions 
341*f6217f89SApple OSS Distributions /* Initialize the reference count and reserved bits */
342*f6217f89SApple OSS Distributions #define os_ref_init_mask(rc, b, grp, bits) os_ref_init_count_mask((rc), (b), (grp), 1, bits)
343*f6217f89SApple OSS Distributions void os_ref_init_count_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp,
344*f6217f89SApple OSS Distributions     os_ref_count_t init_count, uint32_t init_bits)
345*f6217f89SApple OSS Distributions os_error_if(init_count == 0, "Reference count must be non-zero initialized")
346*f6217f89SApple OSS Distributions os_error_if(b > 26, "Bitwise reference count limited to 26 bits")
347*f6217f89SApple OSS Distributions os_error_if(init_bits >= (1U << b), "Bits out of range");
348*f6217f89SApple OSS Distributions 
349*f6217f89SApple OSS Distributions static uint32_t os_ref_get_raw_mask(os_ref_atomic_t *rc);
350*f6217f89SApple OSS Distributions static uint32_t os_ref_get_bits_mask(os_ref_atomic_t *rc, uint32_t b);
351*f6217f89SApple OSS Distributions static os_ref_count_t os_ref_get_count_mask(os_ref_atomic_t *rc, uint32_t b);
352*f6217f89SApple OSS Distributions 
353*f6217f89SApple OSS Distributions static void
354*f6217f89SApple OSS Distributions os_ref_retain_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp);
355*f6217f89SApple OSS Distributions static void
356*f6217f89SApple OSS Distributions os_ref_retain_acquire_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp);
357*f6217f89SApple OSS Distributions static uint32_t
358*f6217f89SApple OSS Distributions os_ref_retain_try_mask(os_ref_atomic_t *, uint32_t b, uint32_t reject_mask,
359*f6217f89SApple OSS Distributions     struct os_refgrp *grp) OS_WARN_RESULT;
360*f6217f89SApple OSS Distributions static bool
361*f6217f89SApple OSS Distributions os_ref_retain_try_acquire_mask(os_ref_atomic_t *, uint32_t b, uint32_t reject_mask,
362*f6217f89SApple OSS Distributions     struct os_refgrp *grp) OS_WARN_RESULT;
363*f6217f89SApple OSS Distributions 
364*f6217f89SApple OSS Distributions static uint32_t
365*f6217f89SApple OSS Distributions os_ref_release_raw_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp) OS_WARN_RESULT;
366*f6217f89SApple OSS Distributions static uint32_t
367*f6217f89SApple OSS Distributions os_ref_release_raw_relaxed_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp) OS_WARN_RESULT;
368*f6217f89SApple OSS Distributions static os_ref_count_t
369*f6217f89SApple OSS Distributions os_ref_release_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp) OS_WARN_RESULT;
370*f6217f89SApple OSS Distributions static os_ref_count_t
371*f6217f89SApple OSS Distributions os_ref_release_relaxed_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp) OS_WARN_RESULT;
372*f6217f89SApple OSS Distributions static uint32_t
373*f6217f89SApple OSS Distributions os_ref_release_live_raw_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp);
374*f6217f89SApple OSS Distributions static void
375*f6217f89SApple OSS Distributions os_ref_release_live_mask(os_ref_atomic_t *rc, uint32_t b, struct os_refgrp *grp);
376*f6217f89SApple OSS Distributions 
377*f6217f89SApple OSS Distributions #pragma GCC visibility pop
378*f6217f89SApple OSS Distributions #endif /* XNU_KERNEL_PRIVATE */
379*f6217f89SApple OSS Distributions 
380*f6217f89SApple OSS Distributions __END_DECLS
381*f6217f89SApple OSS Distributions 
382*f6217f89SApple OSS Distributions #include <os/refcnt_internal.h>
383*f6217f89SApple OSS Distributions #endif
384