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