2 * Copyright (c) 2020 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #ifndef _SYS_EXISLOCK2_H_
35 #define _SYS_EXISLOCK2_H_
37 #ifndef _SYS_GLOBALDATA_H_
38 #include <sys/globaldata.h>
40 #ifndef _MACHINE_THREAD_H_
41 #include <machine/thread.h>
45 * Initialize the structure
48 exis_init(exislock_t *xlk)
50 xlk->pseudo_ticks = 0;
54 * pcpu exis lock API. Enter and and exit a type-safe critical section.
57 exis_hold_gd(globaldata_t gd)
63 exis_drop_gd(globaldata_t gd)
65 if (--gd->gd_exislockcnt == 0)
82 * poll whether the object is usable or not. A value >= 0 indicates that
83 * the (possibly cached) object is usable.
85 * This call returns the approximate number of pseudo_ticks remaining until
86 * the object becomes unusable, +/- one.
88 * The actual value returns is either >= 0, or a negative number. Caller
89 * should refrain from trying to interpret values >= 0 other than the fact
92 * Negative numbers indicate the number of pseudo_ticks which have occurred
93 * since the object became unusable. Various negative values trigger
97 exis_poll(exislock_t *xlk)
99 long val = xlk->pseudo_ticks;
104 return (val - pseudo_ticks);
108 * Return the current state. Note that the NOTCACHED state persists for
109 * two pseudo_ticks. This is done because the global pseudo_ticks counter
110 * can concurrently increment by 1 (but no more than 1) during a type-safe
113 * The state can transition even while holding a type-safe critical section,
114 * but sequencing is designed such that this does not cause any problems.
117 exis_state(exislock_t *xlk)
119 long val = xlk->pseudo_ticks;
124 val = val - pseudo_ticks;
128 return EXIS_NOTCACHED;
129 return EXIS_TERMINATE;
133 * Returns non-zero if the structure is usable (either LIVE or CACHED).
135 * WARNING! The structure is not considered to be usable if it is in
136 * an UNCACHED state, but if it is CACHED and transitions to
137 * UNCACHED during a type-safe critical section it does remain
138 * usable for the duration of that type-safe critical section.
141 exis_usable(exislock_t *xlk)
143 return (exis_poll(xlk) >= 0);
147 * Returns non-zero if the structure can be destroyed
150 exis_freeable(exislock_t *xlk)
152 return (exis_poll(xlk) <= -2);
156 * If the structure is in a LIVE or CACHED state, or if it was CACHED and
157 * concurrently transitioned to NOTCACHED in the same type-safe critical
158 * section, the state will be reset to a CACHED(n) state and non-zero is
161 * Otherwise 0 is returned and no action is taken.
164 exis_cache(exislock_t *xlk, long n)
166 long val = xlk->pseudo_ticks;
167 long pticks = pseudo_ticks;
174 * avoid cache line ping-pong
177 if (xlk->pseudo_ticks != pticks) {
179 xlk->pseudo_ticks = pticks;
187 * Termination sequencing.
189 * The structure is placed in a CACHED(0) state if LIVE or CACHED.
190 * The NOTCACHED state should not be acted upon by the caller until
191 * and unless it transitions to TERMINATE.
193 * Upon returning EXIS_TERMINATE, the structure is returned to a
194 * NOTCACHED state and another 1-2 pseudo ticks will pass until it goes
195 * back to EXIS_TERMINATE (if needed by the caller). Once the caller
196 * is fully satisfied, it may repurpose or destroy the structure.
198 * Caller should hold a strong interlock on the structure in addition
199 * to being in a type-safe critical section.
201 static __inline exis_state_t
202 exis_terminate(exislock_t *xlk)
206 state = exis_state(xlk);
210 * Set to NOTCACHED state and return EXIS_TERMINATE.
211 * due to pseudo_ticks races, the NOTCACHED state will
212 * persist for 1-2 pseudo ticks.
214 xlk->pseudo_ticks = pseudo_ticks - 1;
215 state = EXIS_TERMINATE;
221 xlk->pseudo_ticks = pseudo_ticks;
227 #endif /* !_SYS_EXISLOCK2_H_ */