xref: /freebsd/sys/contrib/ck/include/ck_hp_fifo.h (revision 4f9d94bf6491250b649f5bc931b6d93e68373005)
1*1fb62fb0SOlivier Houchard /*
2*1fb62fb0SOlivier Houchard  * Copyright 2010-2015 Samy Al Bahra.
3*1fb62fb0SOlivier Houchard  * Copyright 2011 David Joseph.
4*1fb62fb0SOlivier Houchard  * All rights reserved.
5*1fb62fb0SOlivier Houchard  *
6*1fb62fb0SOlivier Houchard  * Redistribution and use in source and binary forms, with or without
7*1fb62fb0SOlivier Houchard  * modification, are permitted provided that the following conditions
8*1fb62fb0SOlivier Houchard  * are met:
9*1fb62fb0SOlivier Houchard  * 1. Redistributions of source code must retain the above copyright
10*1fb62fb0SOlivier Houchard  *    notice, this list of conditions and the following disclaimer.
11*1fb62fb0SOlivier Houchard  * 2. Redistributions in binary form must reproduce the above copyright
12*1fb62fb0SOlivier Houchard  *    notice, this list of conditions and the following disclaimer in the
13*1fb62fb0SOlivier Houchard  *    documentation and/or other materials provided with the distribution.
14*1fb62fb0SOlivier Houchard  *
15*1fb62fb0SOlivier Houchard  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*1fb62fb0SOlivier Houchard  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*1fb62fb0SOlivier Houchard  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*1fb62fb0SOlivier Houchard  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*1fb62fb0SOlivier Houchard  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*1fb62fb0SOlivier Houchard  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*1fb62fb0SOlivier Houchard  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*1fb62fb0SOlivier Houchard  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*1fb62fb0SOlivier Houchard  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*1fb62fb0SOlivier Houchard  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*1fb62fb0SOlivier Houchard  * SUCH DAMAGE.
26*1fb62fb0SOlivier Houchard  */
27*1fb62fb0SOlivier Houchard 
28*1fb62fb0SOlivier Houchard #ifndef CK_HP_FIFO_H
29*1fb62fb0SOlivier Houchard #define CK_HP_FIFO_H
30*1fb62fb0SOlivier Houchard 
31*1fb62fb0SOlivier Houchard #include <ck_cc.h>
32*1fb62fb0SOlivier Houchard #include <ck_hp.h>
33*1fb62fb0SOlivier Houchard #include <ck_pr.h>
34*1fb62fb0SOlivier Houchard #include <ck_stddef.h>
35*1fb62fb0SOlivier Houchard 
36*1fb62fb0SOlivier Houchard #define CK_HP_FIFO_SLOTS_COUNT (2)
37*1fb62fb0SOlivier Houchard #define CK_HP_FIFO_SLOTS_SIZE  (sizeof(void *) * CK_HP_FIFO_SLOTS_COUNT)
38*1fb62fb0SOlivier Houchard 
39*1fb62fb0SOlivier Houchard /*
40*1fb62fb0SOlivier Houchard  * Though it is possible to embed the data structure, measurements need
41*1fb62fb0SOlivier Houchard  * to be made for the cost of this. If we were to embed the hazard pointer
42*1fb62fb0SOlivier Houchard  * state into the data structure, this means every deferred reclamation
43*1fb62fb0SOlivier Houchard  * will also include a cache invalidation when linking into the hazard pointer
44*1fb62fb0SOlivier Houchard  * pending queue. This may lead to terrible cache line bouncing.
45*1fb62fb0SOlivier Houchard  */
46*1fb62fb0SOlivier Houchard struct ck_hp_fifo_entry {
47*1fb62fb0SOlivier Houchard 	void *value;
48*1fb62fb0SOlivier Houchard 	ck_hp_hazard_t hazard;
49*1fb62fb0SOlivier Houchard 	struct ck_hp_fifo_entry *next;
50*1fb62fb0SOlivier Houchard };
51*1fb62fb0SOlivier Houchard typedef struct ck_hp_fifo_entry ck_hp_fifo_entry_t;
52*1fb62fb0SOlivier Houchard 
53*1fb62fb0SOlivier Houchard struct ck_hp_fifo {
54*1fb62fb0SOlivier Houchard 	struct ck_hp_fifo_entry *head;
55*1fb62fb0SOlivier Houchard 	struct ck_hp_fifo_entry *tail;
56*1fb62fb0SOlivier Houchard };
57*1fb62fb0SOlivier Houchard typedef struct ck_hp_fifo ck_hp_fifo_t;
58*1fb62fb0SOlivier Houchard 
59*1fb62fb0SOlivier Houchard CK_CC_INLINE static void
ck_hp_fifo_init(struct ck_hp_fifo * fifo,struct ck_hp_fifo_entry * stub)60*1fb62fb0SOlivier Houchard ck_hp_fifo_init(struct ck_hp_fifo *fifo, struct ck_hp_fifo_entry *stub)
61*1fb62fb0SOlivier Houchard {
62*1fb62fb0SOlivier Houchard 
63*1fb62fb0SOlivier Houchard 	fifo->head = fifo->tail = stub;
64*1fb62fb0SOlivier Houchard 	stub->next = NULL;
65*1fb62fb0SOlivier Houchard 	return;
66*1fb62fb0SOlivier Houchard }
67*1fb62fb0SOlivier Houchard 
68*1fb62fb0SOlivier Houchard CK_CC_INLINE static void
ck_hp_fifo_deinit(struct ck_hp_fifo * fifo,struct ck_hp_fifo_entry ** stub)69*1fb62fb0SOlivier Houchard ck_hp_fifo_deinit(struct ck_hp_fifo *fifo, struct ck_hp_fifo_entry **stub)
70*1fb62fb0SOlivier Houchard {
71*1fb62fb0SOlivier Houchard 
72*1fb62fb0SOlivier Houchard 	*stub = fifo->head;
73*1fb62fb0SOlivier Houchard 	fifo->head = fifo->tail = NULL;
74*1fb62fb0SOlivier Houchard 	return;
75*1fb62fb0SOlivier Houchard }
76*1fb62fb0SOlivier Houchard 
77*1fb62fb0SOlivier Houchard CK_CC_INLINE static void
ck_hp_fifo_enqueue_mpmc(ck_hp_record_t * record,struct ck_hp_fifo * fifo,struct ck_hp_fifo_entry * entry,void * value)78*1fb62fb0SOlivier Houchard ck_hp_fifo_enqueue_mpmc(ck_hp_record_t *record,
79*1fb62fb0SOlivier Houchard 			struct ck_hp_fifo *fifo,
80*1fb62fb0SOlivier Houchard 			struct ck_hp_fifo_entry *entry,
81*1fb62fb0SOlivier Houchard 			void *value)
82*1fb62fb0SOlivier Houchard {
83*1fb62fb0SOlivier Houchard 	struct ck_hp_fifo_entry *tail, *next;
84*1fb62fb0SOlivier Houchard 
85*1fb62fb0SOlivier Houchard 	entry->value = value;
86*1fb62fb0SOlivier Houchard 	entry->next = NULL;
87*1fb62fb0SOlivier Houchard 	ck_pr_fence_store_atomic();
88*1fb62fb0SOlivier Houchard 
89*1fb62fb0SOlivier Houchard 	for (;;) {
90*1fb62fb0SOlivier Houchard 		tail = ck_pr_load_ptr(&fifo->tail);
91*1fb62fb0SOlivier Houchard 		ck_hp_set_fence(record, 0, tail);
92*1fb62fb0SOlivier Houchard 		if (tail != ck_pr_load_ptr(&fifo->tail))
93*1fb62fb0SOlivier Houchard 			continue;
94*1fb62fb0SOlivier Houchard 
95*1fb62fb0SOlivier Houchard 		next = ck_pr_load_ptr(&tail->next);
96*1fb62fb0SOlivier Houchard 		if (next != NULL) {
97*1fb62fb0SOlivier Houchard 			ck_pr_cas_ptr(&fifo->tail, tail, next);
98*1fb62fb0SOlivier Houchard 			continue;
99*1fb62fb0SOlivier Houchard 		} else if (ck_pr_cas_ptr(&fifo->tail->next, next, entry) == true)
100*1fb62fb0SOlivier Houchard 			break;
101*1fb62fb0SOlivier Houchard 	}
102*1fb62fb0SOlivier Houchard 
103*1fb62fb0SOlivier Houchard 	ck_pr_fence_atomic();
104*1fb62fb0SOlivier Houchard 	ck_pr_cas_ptr(&fifo->tail, tail, entry);
105*1fb62fb0SOlivier Houchard 	return;
106*1fb62fb0SOlivier Houchard }
107*1fb62fb0SOlivier Houchard 
108*1fb62fb0SOlivier Houchard CK_CC_INLINE static bool
ck_hp_fifo_tryenqueue_mpmc(ck_hp_record_t * record,struct ck_hp_fifo * fifo,struct ck_hp_fifo_entry * entry,void * value)109*1fb62fb0SOlivier Houchard ck_hp_fifo_tryenqueue_mpmc(ck_hp_record_t *record,
110*1fb62fb0SOlivier Houchard 			   struct ck_hp_fifo *fifo,
111*1fb62fb0SOlivier Houchard 			   struct ck_hp_fifo_entry *entry,
112*1fb62fb0SOlivier Houchard 			   void *value)
113*1fb62fb0SOlivier Houchard {
114*1fb62fb0SOlivier Houchard 	struct ck_hp_fifo_entry *tail, *next;
115*1fb62fb0SOlivier Houchard 
116*1fb62fb0SOlivier Houchard 	entry->value = value;
117*1fb62fb0SOlivier Houchard 	entry->next = NULL;
118*1fb62fb0SOlivier Houchard 	ck_pr_fence_store_atomic();
119*1fb62fb0SOlivier Houchard 
120*1fb62fb0SOlivier Houchard 	tail = ck_pr_load_ptr(&fifo->tail);
121*1fb62fb0SOlivier Houchard 	ck_hp_set_fence(record, 0, tail);
122*1fb62fb0SOlivier Houchard 	if (tail != ck_pr_load_ptr(&fifo->tail))
123*1fb62fb0SOlivier Houchard 		return false;
124*1fb62fb0SOlivier Houchard 
125*1fb62fb0SOlivier Houchard 	next = ck_pr_load_ptr(&tail->next);
126*1fb62fb0SOlivier Houchard 	if (next != NULL) {
127*1fb62fb0SOlivier Houchard 		ck_pr_cas_ptr(&fifo->tail, tail, next);
128*1fb62fb0SOlivier Houchard 		return false;
129*1fb62fb0SOlivier Houchard 	} else if (ck_pr_cas_ptr(&fifo->tail->next, next, entry) == false)
130*1fb62fb0SOlivier Houchard 		return false;
131*1fb62fb0SOlivier Houchard 
132*1fb62fb0SOlivier Houchard 	ck_pr_fence_atomic();
133*1fb62fb0SOlivier Houchard 	ck_pr_cas_ptr(&fifo->tail, tail, entry);
134*1fb62fb0SOlivier Houchard 	return true;
135*1fb62fb0SOlivier Houchard }
136*1fb62fb0SOlivier Houchard 
137*1fb62fb0SOlivier Houchard CK_CC_INLINE static struct ck_hp_fifo_entry *
ck_hp_fifo_dequeue_mpmc(ck_hp_record_t * record,struct ck_hp_fifo * fifo,void * value)138*1fb62fb0SOlivier Houchard ck_hp_fifo_dequeue_mpmc(ck_hp_record_t *record,
139*1fb62fb0SOlivier Houchard 			struct ck_hp_fifo *fifo,
140*1fb62fb0SOlivier Houchard 			void *value)
141*1fb62fb0SOlivier Houchard {
142*1fb62fb0SOlivier Houchard 	struct ck_hp_fifo_entry *head, *tail, *next;
143*1fb62fb0SOlivier Houchard 
144*1fb62fb0SOlivier Houchard 	for (;;) {
145*1fb62fb0SOlivier Houchard 		head = ck_pr_load_ptr(&fifo->head);
146*1fb62fb0SOlivier Houchard 		ck_pr_fence_load();
147*1fb62fb0SOlivier Houchard 		tail = ck_pr_load_ptr(&fifo->tail);
148*1fb62fb0SOlivier Houchard 		ck_hp_set_fence(record, 0, head);
149*1fb62fb0SOlivier Houchard 		if (head != ck_pr_load_ptr(&fifo->head))
150*1fb62fb0SOlivier Houchard 			continue;
151*1fb62fb0SOlivier Houchard 
152*1fb62fb0SOlivier Houchard 		next = ck_pr_load_ptr(&head->next);
153*1fb62fb0SOlivier Houchard 		ck_hp_set_fence(record, 1, next);
154*1fb62fb0SOlivier Houchard 		if (head != ck_pr_load_ptr(&fifo->head))
155*1fb62fb0SOlivier Houchard 			continue;
156*1fb62fb0SOlivier Houchard 
157*1fb62fb0SOlivier Houchard 		if (head == tail) {
158*1fb62fb0SOlivier Houchard 			if (next == NULL)
159*1fb62fb0SOlivier Houchard 				return NULL;
160*1fb62fb0SOlivier Houchard 
161*1fb62fb0SOlivier Houchard 			ck_pr_cas_ptr(&fifo->tail, tail, next);
162*1fb62fb0SOlivier Houchard 			continue;
163*1fb62fb0SOlivier Houchard 		} else if (ck_pr_cas_ptr(&fifo->head, head, next) == true)
164*1fb62fb0SOlivier Houchard 			break;
165*1fb62fb0SOlivier Houchard 	}
166*1fb62fb0SOlivier Houchard 
167*1fb62fb0SOlivier Houchard 	ck_pr_store_ptr_unsafe(value, next->value);
168*1fb62fb0SOlivier Houchard 	return head;
169*1fb62fb0SOlivier Houchard }
170*1fb62fb0SOlivier Houchard 
171*1fb62fb0SOlivier Houchard CK_CC_INLINE static struct ck_hp_fifo_entry *
ck_hp_fifo_trydequeue_mpmc(ck_hp_record_t * record,struct ck_hp_fifo * fifo,void * value)172*1fb62fb0SOlivier Houchard ck_hp_fifo_trydequeue_mpmc(ck_hp_record_t *record,
173*1fb62fb0SOlivier Houchard 			   struct ck_hp_fifo *fifo,
174*1fb62fb0SOlivier Houchard 			   void *value)
175*1fb62fb0SOlivier Houchard {
176*1fb62fb0SOlivier Houchard 	struct ck_hp_fifo_entry *head, *tail, *next;
177*1fb62fb0SOlivier Houchard 
178*1fb62fb0SOlivier Houchard 	head = ck_pr_load_ptr(&fifo->head);
179*1fb62fb0SOlivier Houchard 	ck_pr_fence_load();
180*1fb62fb0SOlivier Houchard 	tail = ck_pr_load_ptr(&fifo->tail);
181*1fb62fb0SOlivier Houchard 	ck_hp_set_fence(record, 0, head);
182*1fb62fb0SOlivier Houchard 	if (head != ck_pr_load_ptr(&fifo->head))
183*1fb62fb0SOlivier Houchard 		return NULL;
184*1fb62fb0SOlivier Houchard 
185*1fb62fb0SOlivier Houchard 	next = ck_pr_load_ptr(&head->next);
186*1fb62fb0SOlivier Houchard 	ck_hp_set_fence(record, 1, next);
187*1fb62fb0SOlivier Houchard 	if (head != ck_pr_load_ptr(&fifo->head))
188*1fb62fb0SOlivier Houchard 		return NULL;
189*1fb62fb0SOlivier Houchard 
190*1fb62fb0SOlivier Houchard 	if (head == tail) {
191*1fb62fb0SOlivier Houchard 		if (next == NULL)
192*1fb62fb0SOlivier Houchard 			return NULL;
193*1fb62fb0SOlivier Houchard 
194*1fb62fb0SOlivier Houchard 		ck_pr_cas_ptr(&fifo->tail, tail, next);
195*1fb62fb0SOlivier Houchard 		return NULL;
196*1fb62fb0SOlivier Houchard 	} else if (ck_pr_cas_ptr(&fifo->head, head, next) == false)
197*1fb62fb0SOlivier Houchard 		return NULL;
198*1fb62fb0SOlivier Houchard 
199*1fb62fb0SOlivier Houchard 	ck_pr_store_ptr_unsafe(value, next->value);
200*1fb62fb0SOlivier Houchard 	return head;
201*1fb62fb0SOlivier Houchard }
202*1fb62fb0SOlivier Houchard 
203*1fb62fb0SOlivier Houchard #define CK_HP_FIFO_ISEMPTY(f) ((f)->head->next == NULL)
204*1fb62fb0SOlivier Houchard #define CK_HP_FIFO_FIRST(f)   ((f)->head->next)
205*1fb62fb0SOlivier Houchard #define CK_HP_FIFO_NEXT(m)    ((m)->next)
206*1fb62fb0SOlivier Houchard #define CK_HP_FIFO_FOREACH(fifo, entry)                       	\
207*1fb62fb0SOlivier Houchard         for ((entry) = CK_HP_FIFO_FIRST(fifo);                	\
208*1fb62fb0SOlivier Houchard              (entry) != NULL;                                   \
209*1fb62fb0SOlivier Houchard              (entry) = CK_HP_FIFO_NEXT(entry))
210*1fb62fb0SOlivier Houchard #define CK_HP_FIFO_FOREACH_SAFE(fifo, entry, T)			\
211*1fb62fb0SOlivier Houchard         for ((entry) = CK_HP_FIFO_FIRST(fifo);			\
212*1fb62fb0SOlivier Houchard              (entry) != NULL && ((T) = (entry)->next, 1);	\
213*1fb62fb0SOlivier Houchard              (entry) = (T))
214*1fb62fb0SOlivier Houchard 
215*1fb62fb0SOlivier Houchard #endif /* CK_HP_FIFO_H */
216