1*22ce4affSfengbojiang /*
2*22ce4affSfengbojiang * Copyright 2009-2015 Samy Al Bahra.
3*22ce4affSfengbojiang * All rights reserved.
4*22ce4affSfengbojiang *
5*22ce4affSfengbojiang * Redistribution and use in source and binary forms, with or without
6*22ce4affSfengbojiang * modification, are permitted provided that the following conditions
7*22ce4affSfengbojiang * are met:
8*22ce4affSfengbojiang * 1. Redistributions of source code must retain the above copyright
9*22ce4affSfengbojiang * notice, this list of conditions and the following disclaimer.
10*22ce4affSfengbojiang * 2. Redistributions in binary form must reproduce the above copyright
11*22ce4affSfengbojiang * notice, this list of conditions and the following disclaimer in the
12*22ce4affSfengbojiang * documentation and/or other materials provided with the distribution.
13*22ce4affSfengbojiang *
14*22ce4affSfengbojiang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*22ce4affSfengbojiang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*22ce4affSfengbojiang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*22ce4affSfengbojiang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*22ce4affSfengbojiang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*22ce4affSfengbojiang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*22ce4affSfengbojiang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*22ce4affSfengbojiang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*22ce4affSfengbojiang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*22ce4affSfengbojiang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*22ce4affSfengbojiang * SUCH DAMAGE.
25*22ce4affSfengbojiang */
26*22ce4affSfengbojiang
27*22ce4affSfengbojiang #ifndef CK_STACK_H
28*22ce4affSfengbojiang #define CK_STACK_H
29*22ce4affSfengbojiang
30*22ce4affSfengbojiang #include <ck_cc.h>
31*22ce4affSfengbojiang #include <ck_pr.h>
32*22ce4affSfengbojiang #include <ck_stdbool.h>
33*22ce4affSfengbojiang #include <ck_stddef.h>
34*22ce4affSfengbojiang
35*22ce4affSfengbojiang struct ck_stack_entry {
36*22ce4affSfengbojiang struct ck_stack_entry *next;
37*22ce4affSfengbojiang };
38*22ce4affSfengbojiang typedef struct ck_stack_entry ck_stack_entry_t;
39*22ce4affSfengbojiang
40*22ce4affSfengbojiang struct ck_stack {
41*22ce4affSfengbojiang struct ck_stack_entry *head;
42*22ce4affSfengbojiang char *generation CK_CC_PACKED;
43*22ce4affSfengbojiang } CK_CC_ALIASED;
44*22ce4affSfengbojiang typedef struct ck_stack ck_stack_t;
45*22ce4affSfengbojiang
46*22ce4affSfengbojiang #define CK_STACK_INITIALIZER { NULL, NULL }
47*22ce4affSfengbojiang
48*22ce4affSfengbojiang #ifndef CK_F_STACK_PUSH_UPMC
49*22ce4affSfengbojiang #define CK_F_STACK_PUSH_UPMC
50*22ce4affSfengbojiang /*
51*22ce4affSfengbojiang * Stack producer operation safe for multiple unique producers and multiple consumers.
52*22ce4affSfengbojiang */
53*22ce4affSfengbojiang CK_CC_INLINE static void
ck_stack_push_upmc(struct ck_stack * target,struct ck_stack_entry * entry)54*22ce4affSfengbojiang ck_stack_push_upmc(struct ck_stack *target, struct ck_stack_entry *entry)
55*22ce4affSfengbojiang {
56*22ce4affSfengbojiang struct ck_stack_entry *stack;
57*22ce4affSfengbojiang
58*22ce4affSfengbojiang stack = ck_pr_load_ptr(&target->head);
59*22ce4affSfengbojiang entry->next = stack;
60*22ce4affSfengbojiang ck_pr_fence_store();
61*22ce4affSfengbojiang
62*22ce4affSfengbojiang while (ck_pr_cas_ptr_value(&target->head, stack, entry, &stack) == false) {
63*22ce4affSfengbojiang entry->next = stack;
64*22ce4affSfengbojiang ck_pr_fence_store();
65*22ce4affSfengbojiang }
66*22ce4affSfengbojiang
67*22ce4affSfengbojiang return;
68*22ce4affSfengbojiang }
69*22ce4affSfengbojiang #endif /* CK_F_STACK_PUSH_UPMC */
70*22ce4affSfengbojiang
71*22ce4affSfengbojiang #ifndef CK_F_STACK_TRYPUSH_UPMC
72*22ce4affSfengbojiang #define CK_F_STACK_TRYPUSH_UPMC
73*22ce4affSfengbojiang /*
74*22ce4affSfengbojiang * Stack producer operation for multiple unique producers and multiple consumers.
75*22ce4affSfengbojiang * Returns true on success and false on failure.
76*22ce4affSfengbojiang */
77*22ce4affSfengbojiang CK_CC_INLINE static bool
ck_stack_trypush_upmc(struct ck_stack * target,struct ck_stack_entry * entry)78*22ce4affSfengbojiang ck_stack_trypush_upmc(struct ck_stack *target, struct ck_stack_entry *entry)
79*22ce4affSfengbojiang {
80*22ce4affSfengbojiang struct ck_stack_entry *stack;
81*22ce4affSfengbojiang
82*22ce4affSfengbojiang stack = ck_pr_load_ptr(&target->head);
83*22ce4affSfengbojiang entry->next = stack;
84*22ce4affSfengbojiang ck_pr_fence_store();
85*22ce4affSfengbojiang
86*22ce4affSfengbojiang return ck_pr_cas_ptr(&target->head, stack, entry);
87*22ce4affSfengbojiang }
88*22ce4affSfengbojiang #endif /* CK_F_STACK_TRYPUSH_UPMC */
89*22ce4affSfengbojiang
90*22ce4affSfengbojiang #ifndef CK_F_STACK_POP_UPMC
91*22ce4affSfengbojiang #define CK_F_STACK_POP_UPMC
92*22ce4affSfengbojiang /*
93*22ce4affSfengbojiang * Stack consumer operation safe for multiple unique producers and multiple consumers.
94*22ce4affSfengbojiang */
95*22ce4affSfengbojiang CK_CC_INLINE static struct ck_stack_entry *
ck_stack_pop_upmc(struct ck_stack * target)96*22ce4affSfengbojiang ck_stack_pop_upmc(struct ck_stack *target)
97*22ce4affSfengbojiang {
98*22ce4affSfengbojiang struct ck_stack_entry *entry, *next;
99*22ce4affSfengbojiang
100*22ce4affSfengbojiang entry = ck_pr_load_ptr(&target->head);
101*22ce4affSfengbojiang if (entry == NULL)
102*22ce4affSfengbojiang return NULL;
103*22ce4affSfengbojiang
104*22ce4affSfengbojiang ck_pr_fence_load();
105*22ce4affSfengbojiang next = entry->next;
106*22ce4affSfengbojiang while (ck_pr_cas_ptr_value(&target->head, entry, next, &entry) == false) {
107*22ce4affSfengbojiang if (entry == NULL)
108*22ce4affSfengbojiang break;
109*22ce4affSfengbojiang
110*22ce4affSfengbojiang ck_pr_fence_load();
111*22ce4affSfengbojiang next = entry->next;
112*22ce4affSfengbojiang }
113*22ce4affSfengbojiang
114*22ce4affSfengbojiang return entry;
115*22ce4affSfengbojiang }
116*22ce4affSfengbojiang #endif
117*22ce4affSfengbojiang
118*22ce4affSfengbojiang #ifndef CK_F_STACK_TRYPOP_UPMC
119*22ce4affSfengbojiang #define CK_F_STACK_TRYPOP_UPMC
120*22ce4affSfengbojiang /*
121*22ce4affSfengbojiang * Stack production operation for multiple unique producers and multiple consumers.
122*22ce4affSfengbojiang * Returns true on success and false on failure. The value pointed to by the second
123*22ce4affSfengbojiang * argument is set to a valid ck_stack_entry_t reference if true is returned. If
124*22ce4affSfengbojiang * false is returned, then the value pointed to by the second argument is undefined.
125*22ce4affSfengbojiang */
126*22ce4affSfengbojiang CK_CC_INLINE static bool
ck_stack_trypop_upmc(struct ck_stack * target,struct ck_stack_entry ** r)127*22ce4affSfengbojiang ck_stack_trypop_upmc(struct ck_stack *target, struct ck_stack_entry **r)
128*22ce4affSfengbojiang {
129*22ce4affSfengbojiang struct ck_stack_entry *entry;
130*22ce4affSfengbojiang
131*22ce4affSfengbojiang entry = ck_pr_load_ptr(&target->head);
132*22ce4affSfengbojiang if (entry == NULL)
133*22ce4affSfengbojiang return false;
134*22ce4affSfengbojiang
135*22ce4affSfengbojiang ck_pr_fence_load();
136*22ce4affSfengbojiang if (ck_pr_cas_ptr(&target->head, entry, entry->next) == true) {
137*22ce4affSfengbojiang *r = entry;
138*22ce4affSfengbojiang return true;
139*22ce4affSfengbojiang }
140*22ce4affSfengbojiang
141*22ce4affSfengbojiang return false;
142*22ce4affSfengbojiang }
143*22ce4affSfengbojiang #endif /* CK_F_STACK_TRYPOP_UPMC */
144*22ce4affSfengbojiang
145*22ce4affSfengbojiang #ifndef CK_F_STACK_BATCH_POP_UPMC
146*22ce4affSfengbojiang #define CK_F_STACK_BATCH_POP_UPMC
147*22ce4affSfengbojiang /*
148*22ce4affSfengbojiang * Pop all items off the stack.
149*22ce4affSfengbojiang */
150*22ce4affSfengbojiang CK_CC_INLINE static struct ck_stack_entry *
ck_stack_batch_pop_upmc(struct ck_stack * target)151*22ce4affSfengbojiang ck_stack_batch_pop_upmc(struct ck_stack *target)
152*22ce4affSfengbojiang {
153*22ce4affSfengbojiang struct ck_stack_entry *entry;
154*22ce4affSfengbojiang
155*22ce4affSfengbojiang entry = ck_pr_fas_ptr(&target->head, NULL);
156*22ce4affSfengbojiang ck_pr_fence_load();
157*22ce4affSfengbojiang return entry;
158*22ce4affSfengbojiang }
159*22ce4affSfengbojiang #endif /* CK_F_STACK_BATCH_POP_UPMC */
160*22ce4affSfengbojiang
161*22ce4affSfengbojiang #ifndef CK_F_STACK_PUSH_MPMC
162*22ce4affSfengbojiang #define CK_F_STACK_PUSH_MPMC
163*22ce4affSfengbojiang /*
164*22ce4affSfengbojiang * Stack producer operation safe for multiple producers and multiple consumers.
165*22ce4affSfengbojiang */
166*22ce4affSfengbojiang CK_CC_INLINE static void
ck_stack_push_mpmc(struct ck_stack * target,struct ck_stack_entry * entry)167*22ce4affSfengbojiang ck_stack_push_mpmc(struct ck_stack *target, struct ck_stack_entry *entry)
168*22ce4affSfengbojiang {
169*22ce4affSfengbojiang
170*22ce4affSfengbojiang ck_stack_push_upmc(target, entry);
171*22ce4affSfengbojiang return;
172*22ce4affSfengbojiang }
173*22ce4affSfengbojiang #endif /* CK_F_STACK_PUSH_MPMC */
174*22ce4affSfengbojiang
175*22ce4affSfengbojiang #ifndef CK_F_STACK_TRYPUSH_MPMC
176*22ce4affSfengbojiang #define CK_F_STACK_TRYPUSH_MPMC
177*22ce4affSfengbojiang /*
178*22ce4affSfengbojiang * Stack producer operation safe for multiple producers and multiple consumers.
179*22ce4affSfengbojiang */
180*22ce4affSfengbojiang CK_CC_INLINE static bool
ck_stack_trypush_mpmc(struct ck_stack * target,struct ck_stack_entry * entry)181*22ce4affSfengbojiang ck_stack_trypush_mpmc(struct ck_stack *target, struct ck_stack_entry *entry)
182*22ce4affSfengbojiang {
183*22ce4affSfengbojiang
184*22ce4affSfengbojiang return ck_stack_trypush_upmc(target, entry);
185*22ce4affSfengbojiang }
186*22ce4affSfengbojiang #endif /* CK_F_STACK_TRYPUSH_MPMC */
187*22ce4affSfengbojiang
188*22ce4affSfengbojiang #ifdef CK_F_PR_CAS_PTR_2_VALUE
189*22ce4affSfengbojiang #ifndef CK_F_STACK_POP_MPMC
190*22ce4affSfengbojiang #define CK_F_STACK_POP_MPMC
191*22ce4affSfengbojiang /*
192*22ce4affSfengbojiang * Stack consumer operation safe for multiple producers and multiple consumers.
193*22ce4affSfengbojiang */
194*22ce4affSfengbojiang CK_CC_INLINE static struct ck_stack_entry *
ck_stack_pop_mpmc(struct ck_stack * target)195*22ce4affSfengbojiang ck_stack_pop_mpmc(struct ck_stack *target)
196*22ce4affSfengbojiang {
197*22ce4affSfengbojiang struct ck_stack original, update;
198*22ce4affSfengbojiang
199*22ce4affSfengbojiang original.generation = ck_pr_load_ptr(&target->generation);
200*22ce4affSfengbojiang ck_pr_fence_load();
201*22ce4affSfengbojiang original.head = ck_pr_load_ptr(&target->head);
202*22ce4affSfengbojiang if (original.head == NULL)
203*22ce4affSfengbojiang return NULL;
204*22ce4affSfengbojiang
205*22ce4affSfengbojiang /* Order with respect to next pointer. */
206*22ce4affSfengbojiang ck_pr_fence_load();
207*22ce4affSfengbojiang
208*22ce4affSfengbojiang update.generation = original.generation + 1;
209*22ce4affSfengbojiang update.head = original.head->next;
210*22ce4affSfengbojiang
211*22ce4affSfengbojiang while (ck_pr_cas_ptr_2_value(target, &original, &update, &original) == false) {
212*22ce4affSfengbojiang if (original.head == NULL)
213*22ce4affSfengbojiang return NULL;
214*22ce4affSfengbojiang
215*22ce4affSfengbojiang update.generation = original.generation + 1;
216*22ce4affSfengbojiang
217*22ce4affSfengbojiang /* Order with respect to next pointer. */
218*22ce4affSfengbojiang ck_pr_fence_load();
219*22ce4affSfengbojiang update.head = original.head->next;
220*22ce4affSfengbojiang }
221*22ce4affSfengbojiang
222*22ce4affSfengbojiang return original.head;
223*22ce4affSfengbojiang }
224*22ce4affSfengbojiang #endif /* CK_F_STACK_POP_MPMC */
225*22ce4affSfengbojiang
226*22ce4affSfengbojiang #ifndef CK_F_STACK_TRYPOP_MPMC
227*22ce4affSfengbojiang #define CK_F_STACK_TRYPOP_MPMC
228*22ce4affSfengbojiang CK_CC_INLINE static bool
ck_stack_trypop_mpmc(struct ck_stack * target,struct ck_stack_entry ** r)229*22ce4affSfengbojiang ck_stack_trypop_mpmc(struct ck_stack *target, struct ck_stack_entry **r)
230*22ce4affSfengbojiang {
231*22ce4affSfengbojiang struct ck_stack original, update;
232*22ce4affSfengbojiang
233*22ce4affSfengbojiang original.generation = ck_pr_load_ptr(&target->generation);
234*22ce4affSfengbojiang ck_pr_fence_load();
235*22ce4affSfengbojiang original.head = ck_pr_load_ptr(&target->head);
236*22ce4affSfengbojiang if (original.head == NULL)
237*22ce4affSfengbojiang return false;
238*22ce4affSfengbojiang
239*22ce4affSfengbojiang update.generation = original.generation + 1;
240*22ce4affSfengbojiang ck_pr_fence_load();
241*22ce4affSfengbojiang update.head = original.head->next;
242*22ce4affSfengbojiang
243*22ce4affSfengbojiang if (ck_pr_cas_ptr_2_value(target, &original, &update, &original) == true) {
244*22ce4affSfengbojiang *r = original.head;
245*22ce4affSfengbojiang return true;
246*22ce4affSfengbojiang }
247*22ce4affSfengbojiang
248*22ce4affSfengbojiang return false;
249*22ce4affSfengbojiang }
250*22ce4affSfengbojiang #endif /* CK_F_STACK_TRYPOP_MPMC */
251*22ce4affSfengbojiang #endif /* CK_F_PR_CAS_PTR_2_VALUE */
252*22ce4affSfengbojiang
253*22ce4affSfengbojiang #ifndef CK_F_STACK_BATCH_POP_MPMC
254*22ce4affSfengbojiang #define CK_F_STACK_BATCH_POP_MPMC
255*22ce4affSfengbojiang /*
256*22ce4affSfengbojiang * This is equivalent to the UP/MC version as NULL does not need a
257*22ce4affSfengbojiang * a generation count.
258*22ce4affSfengbojiang */
259*22ce4affSfengbojiang CK_CC_INLINE static struct ck_stack_entry *
ck_stack_batch_pop_mpmc(struct ck_stack * target)260*22ce4affSfengbojiang ck_stack_batch_pop_mpmc(struct ck_stack *target)
261*22ce4affSfengbojiang {
262*22ce4affSfengbojiang
263*22ce4affSfengbojiang return ck_stack_batch_pop_upmc(target);
264*22ce4affSfengbojiang }
265*22ce4affSfengbojiang #endif /* CK_F_STACK_BATCH_POP_MPMC */
266*22ce4affSfengbojiang
267*22ce4affSfengbojiang #ifndef CK_F_STACK_PUSH_MPNC
268*22ce4affSfengbojiang #define CK_F_STACK_PUSH_MPNC
269*22ce4affSfengbojiang /*
270*22ce4affSfengbojiang * Stack producer operation safe with no concurrent consumers.
271*22ce4affSfengbojiang */
272*22ce4affSfengbojiang CK_CC_INLINE static void
ck_stack_push_mpnc(struct ck_stack * target,struct ck_stack_entry * entry)273*22ce4affSfengbojiang ck_stack_push_mpnc(struct ck_stack *target, struct ck_stack_entry *entry)
274*22ce4affSfengbojiang {
275*22ce4affSfengbojiang struct ck_stack_entry *stack;
276*22ce4affSfengbojiang
277*22ce4affSfengbojiang entry->next = NULL;
278*22ce4affSfengbojiang ck_pr_fence_store_atomic();
279*22ce4affSfengbojiang stack = ck_pr_fas_ptr(&target->head, entry);
280*22ce4affSfengbojiang ck_pr_store_ptr(&entry->next, stack);
281*22ce4affSfengbojiang ck_pr_fence_store();
282*22ce4affSfengbojiang
283*22ce4affSfengbojiang return;
284*22ce4affSfengbojiang }
285*22ce4affSfengbojiang #endif /* CK_F_STACK_PUSH_MPNC */
286*22ce4affSfengbojiang
287*22ce4affSfengbojiang /*
288*22ce4affSfengbojiang * Stack producer operation for single producer and no concurrent consumers.
289*22ce4affSfengbojiang */
290*22ce4affSfengbojiang CK_CC_INLINE static void
ck_stack_push_spnc(struct ck_stack * target,struct ck_stack_entry * entry)291*22ce4affSfengbojiang ck_stack_push_spnc(struct ck_stack *target, struct ck_stack_entry *entry)
292*22ce4affSfengbojiang {
293*22ce4affSfengbojiang
294*22ce4affSfengbojiang entry->next = target->head;
295*22ce4affSfengbojiang target->head = entry;
296*22ce4affSfengbojiang return;
297*22ce4affSfengbojiang }
298*22ce4affSfengbojiang
299*22ce4affSfengbojiang /*
300*22ce4affSfengbojiang * Stack consumer operation for no concurrent producers and single consumer.
301*22ce4affSfengbojiang */
302*22ce4affSfengbojiang CK_CC_INLINE static struct ck_stack_entry *
ck_stack_pop_npsc(struct ck_stack * target)303*22ce4affSfengbojiang ck_stack_pop_npsc(struct ck_stack *target)
304*22ce4affSfengbojiang {
305*22ce4affSfengbojiang struct ck_stack_entry *n;
306*22ce4affSfengbojiang
307*22ce4affSfengbojiang if (target->head == NULL)
308*22ce4affSfengbojiang return NULL;
309*22ce4affSfengbojiang
310*22ce4affSfengbojiang n = target->head;
311*22ce4affSfengbojiang target->head = n->next;
312*22ce4affSfengbojiang
313*22ce4affSfengbojiang return n;
314*22ce4affSfengbojiang }
315*22ce4affSfengbojiang
316*22ce4affSfengbojiang /*
317*22ce4affSfengbojiang * Pop all items off a stack.
318*22ce4affSfengbojiang */
319*22ce4affSfengbojiang CK_CC_INLINE static struct ck_stack_entry *
ck_stack_batch_pop_npsc(struct ck_stack * target)320*22ce4affSfengbojiang ck_stack_batch_pop_npsc(struct ck_stack *target)
321*22ce4affSfengbojiang {
322*22ce4affSfengbojiang struct ck_stack_entry *n;
323*22ce4affSfengbojiang
324*22ce4affSfengbojiang n = target->head;
325*22ce4affSfengbojiang target->head = NULL;
326*22ce4affSfengbojiang
327*22ce4affSfengbojiang return n;
328*22ce4affSfengbojiang }
329*22ce4affSfengbojiang
330*22ce4affSfengbojiang /*
331*22ce4affSfengbojiang * Stack initialization function. Guarantees initialization across processors.
332*22ce4affSfengbojiang */
333*22ce4affSfengbojiang CK_CC_INLINE static void
ck_stack_init(struct ck_stack * stack)334*22ce4affSfengbojiang ck_stack_init(struct ck_stack *stack)
335*22ce4affSfengbojiang {
336*22ce4affSfengbojiang
337*22ce4affSfengbojiang stack->head = NULL;
338*22ce4affSfengbojiang stack->generation = NULL;
339*22ce4affSfengbojiang return;
340*22ce4affSfengbojiang }
341*22ce4affSfengbojiang
342*22ce4affSfengbojiang /* Defines a container_of functions for */
343*22ce4affSfengbojiang #define CK_STACK_CONTAINER(T, M, N) CK_CC_CONTAINER(ck_stack_entry_t, T, M, N)
344*22ce4affSfengbojiang
345*22ce4affSfengbojiang #define CK_STACK_ISEMPTY(m) ((m)->head == NULL)
346*22ce4affSfengbojiang #define CK_STACK_FIRST(s) ((s)->head)
347*22ce4affSfengbojiang #define CK_STACK_NEXT(m) ((m)->next)
348*22ce4affSfengbojiang #define CK_STACK_FOREACH(stack, entry) \
349*22ce4affSfengbojiang for ((entry) = CK_STACK_FIRST(stack); \
350*22ce4affSfengbojiang (entry) != NULL; \
351*22ce4affSfengbojiang (entry) = CK_STACK_NEXT(entry))
352*22ce4affSfengbojiang #define CK_STACK_FOREACH_SAFE(stack, entry, T) \
353*22ce4affSfengbojiang for ((entry) = CK_STACK_FIRST(stack); \
354*22ce4affSfengbojiang (entry) != NULL && ((T) = (entry)->next, 1); \
355*22ce4affSfengbojiang (entry) = (T))
356*22ce4affSfengbojiang
357*22ce4affSfengbojiang #endif /* CK_STACK_H */
358