X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=urcu%2Fstatic%2Fwfstack.h;h=9bc9519f16f43c87a65974ad1697fecfb242d94e;hb=db182e317b72b20bcf8f3378aac7e18917f07766;hp=cd00de64e2880887ac27cef99b23ea0db1996584;hpb=07c2a4fd64d456aec094e60c41a9287aa6ce2a6b;p=urcu.git diff --git a/urcu/static/wfstack.h b/urcu/static/wfstack.h index cd00de6..9bc9519 100644 --- a/urcu/static/wfstack.h +++ b/urcu/static/wfstack.h @@ -9,7 +9,7 @@ * TO BE INCLUDED ONLY IN LGPL-COMPATIBLE CODE. See urcu/wfstack.h for * linking dynamically with the userspace rcu library. * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010-2012 - Mathieu Desnoyers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -47,9 +47,10 @@ extern "C" { * Stack implementing push, pop, pop_all operations, as well as iterator * on the stack head returned by pop_all. * - * Wait-free operations: cds_wfs_push, __cds_wfs_pop_all. - * Blocking operations: cds_wfs_pop, cds_wfs_pop_all, iteration on stack - * head returned by pop_all. + * Wait-free operations: cds_wfs_push, __cds_wfs_pop_all, cds_wfs_empty, + * cds_wfs_first. + * Blocking operations: cds_wfs_pop, cds_wfs_pop_all, cds_wfs_next, + * iteration on stack head returned by pop_all. * * Synchronization table: * @@ -136,7 +137,7 @@ int _cds_wfs_push(struct cds_wfs_stack *s, struct cds_wfs_node *node) * Waiting for push to complete enqueue and return the next node. */ static inline struct cds_wfs_node * -___cds_wfs_node_sync_next(struct cds_wfs_node *node) +___cds_wfs_node_sync_next(struct cds_wfs_node *node, int blocking) { struct cds_wfs_node *next; int attempt = 0; @@ -145,6 +146,8 @@ ___cds_wfs_node_sync_next(struct cds_wfs_node *node) * Adaptative busy-looping waiting for push to complete. */ while ((next = CMM_LOAD_SHARED(node->next)) == NULL) { + if (!blocking) + return CDS_WFS_WOULDBLOCK; if (++attempt >= CDS_WFS_ADAPT_ATTEMPTS) { poll(NULL, 0, CDS_WFS_WAIT); /* Wait for 10ms */ attempt = 0; @@ -156,6 +159,29 @@ ___cds_wfs_node_sync_next(struct cds_wfs_node *node) return next; } +static inline +struct cds_wfs_node * +___cds_wfs_pop(struct cds_wfs_stack *s, int blocking) +{ + struct cds_wfs_head *head, *new_head; + struct cds_wfs_node *next; + + for (;;) { + head = CMM_LOAD_SHARED(s->head); + if (___cds_wfs_end(head)) + return NULL; + next = ___cds_wfs_node_sync_next(&head->node, blocking); + if (!blocking && next == CDS_WFS_WOULDBLOCK) + return CDS_WFS_WOULDBLOCK; + new_head = caa_container_of(next, struct cds_wfs_head, node); + if (uatomic_cmpxchg(&s->head, head, new_head) == head) + return &head->node; + if (!blocking) + return CDS_WFS_WOULDBLOCK; + /* busy-loop if head changed under us */ + } +} + /* * __cds_wfs_pop_blocking: pop a node from the stack. * @@ -176,19 +202,20 @@ static inline struct cds_wfs_node * ___cds_wfs_pop_blocking(struct cds_wfs_stack *s) { - struct cds_wfs_head *head, *new_head; - struct cds_wfs_node *next; + return ___cds_wfs_pop(s, 1); +} - for (;;) { - head = CMM_LOAD_SHARED(s->head); - if (___cds_wfs_end(head)) - return NULL; - next = ___cds_wfs_node_sync_next(&head->node); - new_head = caa_container_of(next, struct cds_wfs_head, node); - if (uatomic_cmpxchg(&s->head, head, new_head) == head) - return &head->node; - /* busy-loop if head changed under us */ - } +/* + * __cds_wfs_pop_nonblocking: pop a node from the stack. + * + * Same as __cds_wfs_pop_blocking, but returns CDS_WFS_WOULDBLOCK if + * it needs to block. + */ +static inline +struct cds_wfs_node * +___cds_wfs_pop_nonblocking(struct cds_wfs_stack *s) +{ + return ___cds_wfs_pop(s, 0); } /* @@ -283,7 +310,7 @@ _cds_wfs_pop_all_blocking(struct cds_wfs_stack *s) } /* - * cds_wfs_first_blocking: get first node of a popped stack. + * cds_wfs_first: get first node of a popped stack. * * Content written into the node before enqueue is guaranteed to be * consistent, but no other memory ordering is ensured. @@ -291,15 +318,33 @@ _cds_wfs_pop_all_blocking(struct cds_wfs_stack *s) * Used by for-like iteration macros in urcu/wfstack.h: * cds_wfs_for_each_blocking() * cds_wfs_for_each_blocking_safe() + * + * Returns NULL if popped stack is empty, top stack node otherwise. */ static inline struct cds_wfs_node * -_cds_wfs_first_blocking(struct cds_wfs_head *head) +_cds_wfs_first(struct cds_wfs_head *head) { if (___cds_wfs_end(head)) return NULL; return &head->node; } +static inline struct cds_wfs_node * +___cds_wfs_next(struct cds_wfs_node *node, int blocking) +{ + struct cds_wfs_node *next; + + next = ___cds_wfs_node_sync_next(node, blocking); + /* + * CDS_WFS_WOULDBLOCK != CSD_WFS_END, so we can check for end + * even if ___cds_wfs_node_sync_next returns CDS_WFS_WOULDBLOCK, + * and still return CDS_WFS_WOULDBLOCK. + */ + if (___cds_wfs_end(next)) + return NULL; + return next; +} + /* * cds_wfs_next_blocking: get next node of a popped stack. * @@ -309,16 +354,27 @@ _cds_wfs_first_blocking(struct cds_wfs_head *head) * Used by for-like iteration macros in urcu/wfstack.h: * cds_wfs_for_each_blocking() * cds_wfs_for_each_blocking_safe() + * + * Returns NULL if reached end of popped stack, non-NULL next stack + * node otherwise. */ static inline struct cds_wfs_node * _cds_wfs_next_blocking(struct cds_wfs_node *node) { - struct cds_wfs_node *next; + return ___cds_wfs_next(node, 1); +} - next = ___cds_wfs_node_sync_next(node); - if (___cds_wfs_end(next)) - return NULL; - return next; + +/* + * cds_wfs_next_nonblocking: get next node of a popped stack. + * + * Same as cds_wfs_next_blocking, but returns CDS_WFS_WOULDBLOCK if it + * needs to block. + */ +static inline struct cds_wfs_node * +_cds_wfs_next_nonblocking(struct cds_wfs_node *node) +{ + return ___cds_wfs_next(node, 0); } #ifdef __cplusplus