Path: blob/main/sys/contrib/ck/include/ck_stack.h
102412 views
/*1* Copyright 2009-2015 Samy Al Bahra.2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#ifndef CK_STACK_H27#define CK_STACK_H2829#include <ck_cc.h>30#include <ck_pr.h>31#include <ck_stdbool.h>32#include <ck_stddef.h>3334struct ck_stack_entry {35struct ck_stack_entry *next;36};37typedef struct ck_stack_entry ck_stack_entry_t;3839struct ck_stack {40struct ck_stack_entry *head;41char *generation CK_CC_PACKED;42} CK_CC_ALIASED;43typedef struct ck_stack ck_stack_t;4445#define CK_STACK_INITIALIZER { NULL, NULL }4647#ifndef CK_F_STACK_PUSH_UPMC48#define CK_F_STACK_PUSH_UPMC49/*50* Stack producer operation safe for multiple unique producers and multiple consumers.51*/52CK_CC_INLINE static void53ck_stack_push_upmc(struct ck_stack *target, struct ck_stack_entry *entry)54{55struct ck_stack_entry *stack;5657stack = ck_pr_load_ptr(&target->head);58entry->next = stack;59ck_pr_fence_store();6061while (ck_pr_cas_ptr_value(&target->head, stack, entry, &stack) == false) {62entry->next = stack;63ck_pr_fence_store();64}6566return;67}68#endif /* CK_F_STACK_PUSH_UPMC */6970#ifndef CK_F_STACK_TRYPUSH_UPMC71#define CK_F_STACK_TRYPUSH_UPMC72/*73* Stack producer operation for multiple unique producers and multiple consumers.74* Returns true on success and false on failure.75*/76CK_CC_INLINE static bool77ck_stack_trypush_upmc(struct ck_stack *target, struct ck_stack_entry *entry)78{79struct ck_stack_entry *stack;8081stack = ck_pr_load_ptr(&target->head);82entry->next = stack;83ck_pr_fence_store();8485return ck_pr_cas_ptr(&target->head, stack, entry);86}87#endif /* CK_F_STACK_TRYPUSH_UPMC */8889#ifndef CK_F_STACK_POP_UPMC90#define CK_F_STACK_POP_UPMC91/*92* Stack consumer operation safe for multiple unique producers and multiple consumers.93*/94CK_CC_INLINE static struct ck_stack_entry *95ck_stack_pop_upmc(struct ck_stack *target)96{97struct ck_stack_entry *entry, *next;9899entry = ck_pr_load_ptr(&target->head);100if (entry == NULL)101return NULL;102103ck_pr_fence_load();104next = entry->next;105while (ck_pr_cas_ptr_value(&target->head, entry, next, &entry) == false) {106if (entry == NULL)107break;108109ck_pr_fence_load();110next = entry->next;111}112113return entry;114}115#endif116117#ifndef CK_F_STACK_TRYPOP_UPMC118#define CK_F_STACK_TRYPOP_UPMC119/*120* Stack production operation for multiple unique producers and multiple consumers.121* Returns true on success and false on failure. The value pointed to by the second122* argument is set to a valid ck_stack_entry_t reference if true is returned. If123* false is returned, then the value pointed to by the second argument is undefined.124*/125CK_CC_INLINE static bool126ck_stack_trypop_upmc(struct ck_stack *target, struct ck_stack_entry **r)127{128struct ck_stack_entry *entry;129130entry = ck_pr_load_ptr(&target->head);131if (entry == NULL)132return false;133134ck_pr_fence_load();135if (ck_pr_cas_ptr(&target->head, entry, entry->next) == true) {136*r = entry;137return true;138}139140return false;141}142#endif /* CK_F_STACK_TRYPOP_UPMC */143144#ifndef CK_F_STACK_BATCH_POP_UPMC145#define CK_F_STACK_BATCH_POP_UPMC146/*147* Pop all items off the stack.148*/149CK_CC_INLINE static struct ck_stack_entry *150ck_stack_batch_pop_upmc(struct ck_stack *target)151{152struct ck_stack_entry *entry;153154entry = ck_pr_fas_ptr(&target->head, NULL);155ck_pr_fence_load();156return entry;157}158#endif /* CK_F_STACK_BATCH_POP_UPMC */159160#ifndef CK_F_STACK_PUSH_MPMC161#define CK_F_STACK_PUSH_MPMC162/*163* Stack producer operation safe for multiple producers and multiple consumers.164*/165CK_CC_INLINE static void166ck_stack_push_mpmc(struct ck_stack *target, struct ck_stack_entry *entry)167{168169ck_stack_push_upmc(target, entry);170return;171}172#endif /* CK_F_STACK_PUSH_MPMC */173174#ifndef CK_F_STACK_TRYPUSH_MPMC175#define CK_F_STACK_TRYPUSH_MPMC176/*177* Stack producer operation safe for multiple producers and multiple consumers.178*/179CK_CC_INLINE static bool180ck_stack_trypush_mpmc(struct ck_stack *target, struct ck_stack_entry *entry)181{182183return ck_stack_trypush_upmc(target, entry);184}185#endif /* CK_F_STACK_TRYPUSH_MPMC */186187#ifdef CK_F_PR_CAS_PTR_2_VALUE188#ifndef CK_F_STACK_POP_MPMC189#define CK_F_STACK_POP_MPMC190/*191* Stack consumer operation safe for multiple producers and multiple consumers.192*/193CK_CC_INLINE static struct ck_stack_entry *194ck_stack_pop_mpmc(struct ck_stack *target)195{196struct ck_stack original, update;197198original.generation = ck_pr_load_ptr(&target->generation);199ck_pr_fence_load();200original.head = ck_pr_load_ptr(&target->head);201if (original.head == NULL)202return NULL;203204/* Order with respect to next pointer. */205ck_pr_fence_load();206207update.generation = original.generation + 1;208update.head = original.head->next;209210while (ck_pr_cas_ptr_2_value(target, &original, &update, &original) == false) {211if (original.head == NULL)212return NULL;213214update.generation = original.generation + 1;215216/* Order with respect to next pointer. */217ck_pr_fence_load();218update.head = original.head->next;219}220221return original.head;222}223#endif /* CK_F_STACK_POP_MPMC */224225#ifndef CK_F_STACK_TRYPOP_MPMC226#define CK_F_STACK_TRYPOP_MPMC227CK_CC_INLINE static bool228ck_stack_trypop_mpmc(struct ck_stack *target, struct ck_stack_entry **r)229{230struct ck_stack original, update;231232original.generation = ck_pr_load_ptr(&target->generation);233ck_pr_fence_load();234original.head = ck_pr_load_ptr(&target->head);235if (original.head == NULL)236return false;237238update.generation = original.generation + 1;239ck_pr_fence_load();240update.head = original.head->next;241242if (ck_pr_cas_ptr_2_value(target, &original, &update, &original) == true) {243*r = original.head;244return true;245}246247return false;248}249#endif /* CK_F_STACK_TRYPOP_MPMC */250#endif /* CK_F_PR_CAS_PTR_2_VALUE */251252#ifndef CK_F_STACK_BATCH_POP_MPMC253#define CK_F_STACK_BATCH_POP_MPMC254/*255* This is equivalent to the UP/MC version as NULL does not need a256* a generation count.257*/258CK_CC_INLINE static struct ck_stack_entry *259ck_stack_batch_pop_mpmc(struct ck_stack *target)260{261262return ck_stack_batch_pop_upmc(target);263}264#endif /* CK_F_STACK_BATCH_POP_MPMC */265266#ifndef CK_F_STACK_PUSH_MPNC267#define CK_F_STACK_PUSH_MPNC268/*269* Stack producer operation safe with no concurrent consumers.270*/271CK_CC_INLINE static void272ck_stack_push_mpnc(struct ck_stack *target, struct ck_stack_entry *entry)273{274struct ck_stack_entry *stack;275276entry->next = NULL;277ck_pr_fence_store_atomic();278stack = ck_pr_fas_ptr(&target->head, entry);279ck_pr_store_ptr(&entry->next, stack);280ck_pr_fence_store();281282return;283}284#endif /* CK_F_STACK_PUSH_MPNC */285286/*287* Stack producer operation for single producer and no concurrent consumers.288*/289CK_CC_INLINE static void290ck_stack_push_spnc(struct ck_stack *target, struct ck_stack_entry *entry)291{292293entry->next = target->head;294target->head = entry;295return;296}297298/*299* Stack consumer operation for no concurrent producers and single consumer.300*/301CK_CC_INLINE static struct ck_stack_entry *302ck_stack_pop_npsc(struct ck_stack *target)303{304struct ck_stack_entry *n;305306if (target->head == NULL)307return NULL;308309n = target->head;310target->head = n->next;311312return n;313}314315/*316* Pop all items off a stack.317*/318CK_CC_INLINE static struct ck_stack_entry *319ck_stack_batch_pop_npsc(struct ck_stack *target)320{321struct ck_stack_entry *n;322323n = target->head;324target->head = NULL;325326return n;327}328329/*330* Stack initialization function. Guarantees initialization across processors.331*/332CK_CC_INLINE static void333ck_stack_init(struct ck_stack *stack)334{335336stack->head = NULL;337stack->generation = NULL;338return;339}340341/* Defines a container_of functions for */342#define CK_STACK_CONTAINER(T, M, N) CK_CC_CONTAINER(ck_stack_entry_t, T, M, N)343344#define CK_STACK_ISEMPTY(m) ((m)->head == NULL)345#define CK_STACK_FIRST(s) ((s)->head)346#define CK_STACK_NEXT(m) ((m)->next)347#define CK_STACK_FOREACH(stack, entry) \348for ((entry) = CK_STACK_FIRST(stack); \349(entry) != NULL; \350(entry) = CK_STACK_NEXT(entry))351#define CK_STACK_FOREACH_SAFE(stack, entry, T) \352for ((entry) = CK_STACK_FIRST(stack); \353(entry) != NULL && ((T) = (entry)->next, 1); \354(entry) = (T))355356#endif /* CK_STACK_H */357358359