xref: /freebsd/sys/contrib/ck/src/ck_hp.c (revision 4f9d94bf6491250b649f5bc931b6d93e68373005)
1*1fb62fb0SOlivier Houchard /*
2*1fb62fb0SOlivier Houchard  * Copyright 2010-2015 Samy Al Bahra.
3*1fb62fb0SOlivier Houchard  * All rights reserved.
4*1fb62fb0SOlivier Houchard  *
5*1fb62fb0SOlivier Houchard  * Redistribution and use in source and binary forms, with or without
6*1fb62fb0SOlivier Houchard  * modification, are permitted provided that the following conditions
7*1fb62fb0SOlivier Houchard  * are met:
8*1fb62fb0SOlivier Houchard  * 1. Redistributions of source code must retain the above copyright
9*1fb62fb0SOlivier Houchard  *    notice, this list of conditions and the following disclaimer.
10*1fb62fb0SOlivier Houchard  * 2. Redistributions in binary form must reproduce the above copyright
11*1fb62fb0SOlivier Houchard  *    notice, this list of conditions and the following disclaimer in the
12*1fb62fb0SOlivier Houchard  *    documentation and/or other materials provided with the distribution.
13*1fb62fb0SOlivier Houchard  *
14*1fb62fb0SOlivier Houchard  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*1fb62fb0SOlivier Houchard  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*1fb62fb0SOlivier Houchard  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*1fb62fb0SOlivier Houchard  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*1fb62fb0SOlivier Houchard  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*1fb62fb0SOlivier Houchard  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*1fb62fb0SOlivier Houchard  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*1fb62fb0SOlivier Houchard  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*1fb62fb0SOlivier Houchard  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*1fb62fb0SOlivier Houchard  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*1fb62fb0SOlivier Houchard  * SUCH DAMAGE.
25*1fb62fb0SOlivier Houchard  */
26*1fb62fb0SOlivier Houchard 
27*1fb62fb0SOlivier Houchard /*
28*1fb62fb0SOlivier Houchard  * (c) Copyright 2008, IBM Corporation.
29*1fb62fb0SOlivier Houchard  * Licensed under the Apache License, Version 2.0 (the "License");
30*1fb62fb0SOlivier Houchard  * you may not use this file except in compliance with the License.
31*1fb62fb0SOlivier Houchard  * You may obtain a copy of the License at
32*1fb62fb0SOlivier Houchard  *
33*1fb62fb0SOlivier Houchard  * http://www.apache.org/licenses/LICENSE-2.0
34*1fb62fb0SOlivier Houchard  *
35*1fb62fb0SOlivier Houchard  * Unless required by applicable law or agreed to in writing, software
36*1fb62fb0SOlivier Houchard  * distributed under the License is distributed on an "AS IS" BASIS,
37*1fb62fb0SOlivier Houchard  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
38*1fb62fb0SOlivier Houchard  * See the License for the specific language governing permissions and
39*1fb62fb0SOlivier Houchard  * limitations under the License.
40*1fb62fb0SOlivier Houchard  */
41*1fb62fb0SOlivier Houchard 
42*1fb62fb0SOlivier Houchard /*
43*1fb62fb0SOlivier Houchard  * This is an implementation of hazard pointers as detailed in:
44*1fb62fb0SOlivier Houchard  *   http://www.research.ibm.com/people/m/michael/ieeetpds-2004.pdf
45*1fb62fb0SOlivier Houchard  *
46*1fb62fb0SOlivier Houchard  * This API provides a publishing mechanism that defers destruction of
47*1fb62fb0SOlivier Houchard  * hazard pointers until it is safe to do so. Preventing arbitrary re-use
48*1fb62fb0SOlivier Houchard  * protects against the ABA problem and provides safe memory reclamation.
49*1fb62fb0SOlivier Houchard  * The implementation was derived from the Hazard Pointers implementation
50*1fb62fb0SOlivier Houchard  * from the Amino CBBS project. It has been heavily modified for Concurrency
51*1fb62fb0SOlivier Houchard  * Kit.
52*1fb62fb0SOlivier Houchard  */
53*1fb62fb0SOlivier Houchard 
54*1fb62fb0SOlivier Houchard #include <ck_backoff.h>
55*1fb62fb0SOlivier Houchard #include <ck_cc.h>
56*1fb62fb0SOlivier Houchard #include <ck_hp.h>
57*1fb62fb0SOlivier Houchard #include <ck_pr.h>
58*1fb62fb0SOlivier Houchard #include <ck_stack.h>
59*1fb62fb0SOlivier Houchard #include <ck_stdbool.h>
60*1fb62fb0SOlivier Houchard #include <ck_stddef.h>
61*1fb62fb0SOlivier Houchard #include <ck_stdlib.h>
62*1fb62fb0SOlivier Houchard #include <ck_string.h>
63*1fb62fb0SOlivier Houchard 
CK_STACK_CONTAINER(struct ck_hp_record,global_entry,ck_hp_record_container)64*1fb62fb0SOlivier Houchard CK_STACK_CONTAINER(struct ck_hp_record, global_entry, ck_hp_record_container)
65*1fb62fb0SOlivier Houchard CK_STACK_CONTAINER(struct ck_hp_hazard, pending_entry, ck_hp_hazard_container)
66*1fb62fb0SOlivier Houchard 
67*1fb62fb0SOlivier Houchard void
68*1fb62fb0SOlivier Houchard ck_hp_init(struct ck_hp *state,
69*1fb62fb0SOlivier Houchard 	   unsigned int degree,
70*1fb62fb0SOlivier Houchard 	   unsigned int threshold,
71*1fb62fb0SOlivier Houchard 	   ck_hp_destructor_t destroy)
72*1fb62fb0SOlivier Houchard {
73*1fb62fb0SOlivier Houchard 
74*1fb62fb0SOlivier Houchard 	state->threshold = threshold;
75*1fb62fb0SOlivier Houchard 	state->degree = degree;
76*1fb62fb0SOlivier Houchard 	state->destroy = destroy;
77*1fb62fb0SOlivier Houchard 	state->n_subscribers = 0;
78*1fb62fb0SOlivier Houchard 	state->n_free = 0;
79*1fb62fb0SOlivier Houchard 	ck_stack_init(&state->subscribers);
80*1fb62fb0SOlivier Houchard 	ck_pr_fence_store();
81*1fb62fb0SOlivier Houchard 
82*1fb62fb0SOlivier Houchard 	return;
83*1fb62fb0SOlivier Houchard }
84*1fb62fb0SOlivier Houchard 
85*1fb62fb0SOlivier Houchard void
ck_hp_set_threshold(struct ck_hp * state,unsigned int threshold)86*1fb62fb0SOlivier Houchard ck_hp_set_threshold(struct ck_hp *state, unsigned int threshold)
87*1fb62fb0SOlivier Houchard {
88*1fb62fb0SOlivier Houchard 
89*1fb62fb0SOlivier Houchard 	ck_pr_store_uint(&state->threshold, threshold);
90*1fb62fb0SOlivier Houchard 	return;
91*1fb62fb0SOlivier Houchard }
92*1fb62fb0SOlivier Houchard 
93*1fb62fb0SOlivier Houchard struct ck_hp_record *
ck_hp_recycle(struct ck_hp * global)94*1fb62fb0SOlivier Houchard ck_hp_recycle(struct ck_hp *global)
95*1fb62fb0SOlivier Houchard {
96*1fb62fb0SOlivier Houchard 	struct ck_hp_record *record;
97*1fb62fb0SOlivier Houchard 	ck_stack_entry_t *entry;
98*1fb62fb0SOlivier Houchard 	int state;
99*1fb62fb0SOlivier Houchard 
100*1fb62fb0SOlivier Houchard 	if (ck_pr_load_uint(&global->n_free) == 0)
101*1fb62fb0SOlivier Houchard 		return NULL;
102*1fb62fb0SOlivier Houchard 
103*1fb62fb0SOlivier Houchard 	CK_STACK_FOREACH(&global->subscribers, entry) {
104*1fb62fb0SOlivier Houchard 		record = ck_hp_record_container(entry);
105*1fb62fb0SOlivier Houchard 
106*1fb62fb0SOlivier Houchard 		if (ck_pr_load_int(&record->state) == CK_HP_FREE) {
107*1fb62fb0SOlivier Houchard 			ck_pr_fence_load();
108*1fb62fb0SOlivier Houchard 			state = ck_pr_fas_int(&record->state, CK_HP_USED);
109*1fb62fb0SOlivier Houchard 			if (state == CK_HP_FREE) {
110*1fb62fb0SOlivier Houchard 				ck_pr_dec_uint(&global->n_free);
111*1fb62fb0SOlivier Houchard 				return record;
112*1fb62fb0SOlivier Houchard 			}
113*1fb62fb0SOlivier Houchard 		}
114*1fb62fb0SOlivier Houchard 	}
115*1fb62fb0SOlivier Houchard 
116*1fb62fb0SOlivier Houchard 	return NULL;
117*1fb62fb0SOlivier Houchard }
118*1fb62fb0SOlivier Houchard 
119*1fb62fb0SOlivier Houchard void
ck_hp_unregister(struct ck_hp_record * entry)120*1fb62fb0SOlivier Houchard ck_hp_unregister(struct ck_hp_record *entry)
121*1fb62fb0SOlivier Houchard {
122*1fb62fb0SOlivier Houchard 
123*1fb62fb0SOlivier Houchard 	entry->n_pending = 0;
124*1fb62fb0SOlivier Houchard 	entry->n_peak = 0;
125*1fb62fb0SOlivier Houchard 	entry->n_reclamations = 0;
126*1fb62fb0SOlivier Houchard 	ck_stack_init(&entry->pending);
127*1fb62fb0SOlivier Houchard 	ck_pr_fence_store();
128*1fb62fb0SOlivier Houchard 	ck_pr_store_int(&entry->state, CK_HP_FREE);
129*1fb62fb0SOlivier Houchard 	ck_pr_inc_uint(&entry->global->n_free);
130*1fb62fb0SOlivier Houchard 	return;
131*1fb62fb0SOlivier Houchard }
132*1fb62fb0SOlivier Houchard 
133*1fb62fb0SOlivier Houchard void
ck_hp_register(struct ck_hp * state,struct ck_hp_record * entry,void ** pointers)134*1fb62fb0SOlivier Houchard ck_hp_register(struct ck_hp *state,
135*1fb62fb0SOlivier Houchard     struct ck_hp_record *entry,
136*1fb62fb0SOlivier Houchard     void **pointers)
137*1fb62fb0SOlivier Houchard {
138*1fb62fb0SOlivier Houchard 
139*1fb62fb0SOlivier Houchard 	entry->state = CK_HP_USED;
140*1fb62fb0SOlivier Houchard 	entry->global = state;
141*1fb62fb0SOlivier Houchard 	entry->pointers = pointers;
142*1fb62fb0SOlivier Houchard 	entry->n_pending = 0;
143*1fb62fb0SOlivier Houchard 	entry->n_peak = 0;
144*1fb62fb0SOlivier Houchard 	entry->n_reclamations = 0;
145*1fb62fb0SOlivier Houchard 	memset(pointers, 0, state->degree * sizeof(void *));
146*1fb62fb0SOlivier Houchard 	ck_stack_init(&entry->pending);
147*1fb62fb0SOlivier Houchard 	ck_pr_fence_store();
148*1fb62fb0SOlivier Houchard 	ck_stack_push_upmc(&state->subscribers, &entry->global_entry);
149*1fb62fb0SOlivier Houchard 	ck_pr_inc_uint(&state->n_subscribers);
150*1fb62fb0SOlivier Houchard 	return;
151*1fb62fb0SOlivier Houchard }
152*1fb62fb0SOlivier Houchard 
153*1fb62fb0SOlivier Houchard static int
hazard_compare(const void * a,const void * b)154*1fb62fb0SOlivier Houchard hazard_compare(const void *a, const void *b)
155*1fb62fb0SOlivier Houchard {
156*1fb62fb0SOlivier Houchard 	void * const *x;
157*1fb62fb0SOlivier Houchard 	void * const *y;
158*1fb62fb0SOlivier Houchard 
159*1fb62fb0SOlivier Houchard 	x = a;
160*1fb62fb0SOlivier Houchard 	y = b;
161*1fb62fb0SOlivier Houchard 	return ((*x > *y) - (*x < *y));
162*1fb62fb0SOlivier Houchard }
163*1fb62fb0SOlivier Houchard 
164*1fb62fb0SOlivier Houchard CK_CC_INLINE static bool
ck_hp_member_scan(ck_stack_entry_t * entry,unsigned int degree,void * pointer)165*1fb62fb0SOlivier Houchard ck_hp_member_scan(ck_stack_entry_t *entry, unsigned int degree, void *pointer)
166*1fb62fb0SOlivier Houchard {
167*1fb62fb0SOlivier Houchard 	struct ck_hp_record *record;
168*1fb62fb0SOlivier Houchard 	unsigned int i;
169*1fb62fb0SOlivier Houchard 	void *hazard;
170*1fb62fb0SOlivier Houchard 
171*1fb62fb0SOlivier Houchard 	do {
172*1fb62fb0SOlivier Houchard 		record = ck_hp_record_container(entry);
173*1fb62fb0SOlivier Houchard 		if (ck_pr_load_int(&record->state) == CK_HP_FREE)
174*1fb62fb0SOlivier Houchard 			continue;
175*1fb62fb0SOlivier Houchard 
176*1fb62fb0SOlivier Houchard 		if (ck_pr_load_ptr(&record->pointers) == NULL)
177*1fb62fb0SOlivier Houchard 			continue;
178*1fb62fb0SOlivier Houchard 
179*1fb62fb0SOlivier Houchard 		for (i = 0; i < degree; i++) {
180*1fb62fb0SOlivier Houchard 			hazard = ck_pr_load_ptr(&record->pointers[i]);
181*1fb62fb0SOlivier Houchard 			if (hazard == pointer)
182*1fb62fb0SOlivier Houchard 				return (true);
183*1fb62fb0SOlivier Houchard 		}
184*1fb62fb0SOlivier Houchard 	} while ((entry = CK_STACK_NEXT(entry)) != NULL);
185*1fb62fb0SOlivier Houchard 
186*1fb62fb0SOlivier Houchard 	return (false);
187*1fb62fb0SOlivier Houchard }
188*1fb62fb0SOlivier Houchard 
189*1fb62fb0SOlivier Houchard CK_CC_INLINE static void *
ck_hp_member_cache(struct ck_hp * global,void ** cache,unsigned int * n_hazards)190*1fb62fb0SOlivier Houchard ck_hp_member_cache(struct ck_hp *global, void **cache, unsigned int *n_hazards)
191*1fb62fb0SOlivier Houchard {
192*1fb62fb0SOlivier Houchard 	struct ck_hp_record *record;
193*1fb62fb0SOlivier Houchard 	ck_stack_entry_t *entry;
194*1fb62fb0SOlivier Houchard 	unsigned int hazards = 0;
195*1fb62fb0SOlivier Houchard 	unsigned int i;
196*1fb62fb0SOlivier Houchard 	void *pointer;
197*1fb62fb0SOlivier Houchard 
198*1fb62fb0SOlivier Houchard 	CK_STACK_FOREACH(&global->subscribers, entry) {
199*1fb62fb0SOlivier Houchard 		record = ck_hp_record_container(entry);
200*1fb62fb0SOlivier Houchard 		if (ck_pr_load_int(&record->state) == CK_HP_FREE)
201*1fb62fb0SOlivier Houchard 			continue;
202*1fb62fb0SOlivier Houchard 
203*1fb62fb0SOlivier Houchard 		if (ck_pr_load_ptr(&record->pointers) == NULL)
204*1fb62fb0SOlivier Houchard 			continue;
205*1fb62fb0SOlivier Houchard 
206*1fb62fb0SOlivier Houchard 		for (i = 0; i < global->degree; i++) {
207*1fb62fb0SOlivier Houchard 			if (hazards > CK_HP_CACHE)
208*1fb62fb0SOlivier Houchard 				break;
209*1fb62fb0SOlivier Houchard 
210*1fb62fb0SOlivier Houchard 			pointer = ck_pr_load_ptr(&record->pointers[i]);
211*1fb62fb0SOlivier Houchard 			if (pointer != NULL)
212*1fb62fb0SOlivier Houchard 				cache[hazards++] = pointer;
213*1fb62fb0SOlivier Houchard 		}
214*1fb62fb0SOlivier Houchard 	}
215*1fb62fb0SOlivier Houchard 
216*1fb62fb0SOlivier Houchard 	*n_hazards = hazards;
217*1fb62fb0SOlivier Houchard 	return (entry);
218*1fb62fb0SOlivier Houchard }
219*1fb62fb0SOlivier Houchard 
220*1fb62fb0SOlivier Houchard void
ck_hp_reclaim(struct ck_hp_record * thread)221*1fb62fb0SOlivier Houchard ck_hp_reclaim(struct ck_hp_record *thread)
222*1fb62fb0SOlivier Houchard {
223*1fb62fb0SOlivier Houchard 	struct ck_hp_hazard *hazard;
224*1fb62fb0SOlivier Houchard 	struct ck_hp *global = thread->global;
225*1fb62fb0SOlivier Houchard 	unsigned int n_hazards;
226*1fb62fb0SOlivier Houchard 	void **cache, *marker, *match;
227*1fb62fb0SOlivier Houchard 	ck_stack_entry_t *previous, *entry, *next;
228*1fb62fb0SOlivier Houchard 
229*1fb62fb0SOlivier Houchard 	/* Store as many entries as possible in local array. */
230*1fb62fb0SOlivier Houchard 	cache = thread->cache;
231*1fb62fb0SOlivier Houchard 	marker = ck_hp_member_cache(global, cache, &n_hazards);
232*1fb62fb0SOlivier Houchard 
233*1fb62fb0SOlivier Houchard 	/*
234*1fb62fb0SOlivier Houchard 	 * In theory, there is an n such that (n * (log n) ** 2) < np.
235*1fb62fb0SOlivier Houchard 	 */
236*1fb62fb0SOlivier Houchard 	qsort(cache, n_hazards, sizeof(void *), hazard_compare);
237*1fb62fb0SOlivier Houchard 
238*1fb62fb0SOlivier Houchard 	previous = NULL;
239*1fb62fb0SOlivier Houchard 	CK_STACK_FOREACH_SAFE(&thread->pending, entry, next) {
240*1fb62fb0SOlivier Houchard 		hazard = ck_hp_hazard_container(entry);
241*1fb62fb0SOlivier Houchard 		match = bsearch(&hazard->pointer, cache, n_hazards,
242*1fb62fb0SOlivier Houchard 				  sizeof(void *), hazard_compare);
243*1fb62fb0SOlivier Houchard 		if (match != NULL) {
244*1fb62fb0SOlivier Houchard 			previous = entry;
245*1fb62fb0SOlivier Houchard 			continue;
246*1fb62fb0SOlivier Houchard 		}
247*1fb62fb0SOlivier Houchard 
248*1fb62fb0SOlivier Houchard 		if (marker != NULL &&
249*1fb62fb0SOlivier Houchard 		    ck_hp_member_scan(marker, global->degree, hazard->pointer)) {
250*1fb62fb0SOlivier Houchard 			previous = entry;
251*1fb62fb0SOlivier Houchard 			continue;
252*1fb62fb0SOlivier Houchard 		}
253*1fb62fb0SOlivier Houchard 
254*1fb62fb0SOlivier Houchard 		thread->n_pending -= 1;
255*1fb62fb0SOlivier Houchard 
256*1fb62fb0SOlivier Houchard 		/* Remove from the pending stack. */
257*1fb62fb0SOlivier Houchard 		if (previous)
258*1fb62fb0SOlivier Houchard 			CK_STACK_NEXT(previous) = CK_STACK_NEXT(entry);
259*1fb62fb0SOlivier Houchard 		else
260*1fb62fb0SOlivier Houchard 			CK_STACK_FIRST(&thread->pending) = CK_STACK_NEXT(entry);
261*1fb62fb0SOlivier Houchard 
262*1fb62fb0SOlivier Houchard 		/* The entry is now safe to destroy. */
263*1fb62fb0SOlivier Houchard 		global->destroy(hazard->data);
264*1fb62fb0SOlivier Houchard 		thread->n_reclamations++;
265*1fb62fb0SOlivier Houchard 	}
266*1fb62fb0SOlivier Houchard 
267*1fb62fb0SOlivier Houchard 	return;
268*1fb62fb0SOlivier Houchard }
269*1fb62fb0SOlivier Houchard 
270*1fb62fb0SOlivier Houchard void
ck_hp_retire(struct ck_hp_record * thread,struct ck_hp_hazard * hazard,void * data,void * pointer)271*1fb62fb0SOlivier Houchard ck_hp_retire(struct ck_hp_record *thread,
272*1fb62fb0SOlivier Houchard     struct ck_hp_hazard *hazard,
273*1fb62fb0SOlivier Houchard     void *data,
274*1fb62fb0SOlivier Houchard     void *pointer)
275*1fb62fb0SOlivier Houchard {
276*1fb62fb0SOlivier Houchard 
277*1fb62fb0SOlivier Houchard 	ck_pr_store_ptr(&hazard->pointer, pointer);
278*1fb62fb0SOlivier Houchard 	ck_pr_store_ptr(&hazard->data, data);
279*1fb62fb0SOlivier Houchard 	ck_stack_push_spnc(&thread->pending, &hazard->pending_entry);
280*1fb62fb0SOlivier Houchard 
281*1fb62fb0SOlivier Houchard 	thread->n_pending += 1;
282*1fb62fb0SOlivier Houchard 	if (thread->n_pending > thread->n_peak)
283*1fb62fb0SOlivier Houchard 		thread->n_peak = thread->n_pending;
284*1fb62fb0SOlivier Houchard 
285*1fb62fb0SOlivier Houchard 	return;
286*1fb62fb0SOlivier Houchard }
287*1fb62fb0SOlivier Houchard 
288*1fb62fb0SOlivier Houchard void
ck_hp_free(struct ck_hp_record * thread,struct ck_hp_hazard * hazard,void * data,void * pointer)289*1fb62fb0SOlivier Houchard ck_hp_free(struct ck_hp_record *thread,
290*1fb62fb0SOlivier Houchard     struct ck_hp_hazard *hazard,
291*1fb62fb0SOlivier Houchard     void *data,
292*1fb62fb0SOlivier Houchard     void *pointer)
293*1fb62fb0SOlivier Houchard {
294*1fb62fb0SOlivier Houchard 	struct ck_hp *global;
295*1fb62fb0SOlivier Houchard 
296*1fb62fb0SOlivier Houchard 	global = ck_pr_load_ptr(&thread->global);
297*1fb62fb0SOlivier Houchard 	ck_pr_store_ptr(&hazard->data, data);
298*1fb62fb0SOlivier Houchard 	ck_pr_store_ptr(&hazard->pointer, pointer);
299*1fb62fb0SOlivier Houchard 	ck_stack_push_spnc(&thread->pending, &hazard->pending_entry);
300*1fb62fb0SOlivier Houchard 
301*1fb62fb0SOlivier Houchard 	thread->n_pending += 1;
302*1fb62fb0SOlivier Houchard 	if (thread->n_pending > thread->n_peak)
303*1fb62fb0SOlivier Houchard 		thread->n_peak = thread->n_pending;
304*1fb62fb0SOlivier Houchard 
305*1fb62fb0SOlivier Houchard 	if (thread->n_pending >= global->threshold)
306*1fb62fb0SOlivier Houchard 		ck_hp_reclaim(thread);
307*1fb62fb0SOlivier Houchard 
308*1fb62fb0SOlivier Houchard 	return;
309*1fb62fb0SOlivier Houchard }
310*1fb62fb0SOlivier Houchard 
311*1fb62fb0SOlivier Houchard void
ck_hp_purge(struct ck_hp_record * thread)312*1fb62fb0SOlivier Houchard ck_hp_purge(struct ck_hp_record *thread)
313*1fb62fb0SOlivier Houchard {
314*1fb62fb0SOlivier Houchard 	ck_backoff_t backoff = CK_BACKOFF_INITIALIZER;
315*1fb62fb0SOlivier Houchard 
316*1fb62fb0SOlivier Houchard 	while (thread->n_pending > 0) {
317*1fb62fb0SOlivier Houchard 		ck_hp_reclaim(thread);
318*1fb62fb0SOlivier Houchard 		if (thread->n_pending > 0)
319*1fb62fb0SOlivier Houchard 			ck_backoff_eb(&backoff);
320*1fb62fb0SOlivier Houchard 	}
321*1fb62fb0SOlivier Houchard 
322*1fb62fb0SOlivier Houchard 	return;
323*1fb62fb0SOlivier Houchard }
324