From 294d33967723e5db8ec8221f3841deff76475d08 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sun, 22 Aug 2010 08:52:13 -0400 Subject: [PATCH] wfstack: LGPL-ize Create wrapper symbols for LGPL linking. Signed-off-by: Mathieu Desnoyers --- Makefile.am | 3 +- tests/Makefile.am | 8 ++- urcu/wfstack-static.h | 120 ++++++++++++++++++++++++++++++++++++++++++ urcu/wfstack.h | 93 ++++++-------------------------- wfstack.c | 50 ++++++++++++++++++ 5 files changed, 194 insertions(+), 80 deletions(-) create mode 100644 urcu/wfstack-static.h create mode 100644 wfstack.c diff --git a/Makefile.am b/Makefile.am index e56803f..44ab874 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,7 @@ COMPAT+=compat_futex.c endif lib_LTLIBRARIES = liburcu.la liburcu-qsbr.la liburcu-mb.la liburcu-signal.la \ - liburcu-bp.la liburcu-defer.la libwfqueue.la + liburcu-bp.la liburcu-defer.la libwfqueue.la libwfstack.la liburcu_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) @@ -43,3 +43,4 @@ liburcu_bp_la_SOURCES = urcu-bp.c urcu-pointer.c $(COMPAT) liburcu_defer_la_SOURCES = urcu-defer.c $(COMPAT) libwfqueue_la_SOURCES = wfqueue.c $(COMPAT) +libwfstack_la_SOURCES = wfstack.c $(COMPAT) diff --git a/tests/Makefile.am b/tests/Makefile.am index 282b8f9..1d9f88f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -14,7 +14,7 @@ noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \ test_uatomic test_urcu_assign test_urcu_assign_dynamic_link \ test_urcu_bp test_urcu_bp_dynamic_link test_cycles_per_loop \ test_urcu_lfq test_urcu_wfq test_urcu_lfs test_urcu_wfs \ - test_urcu_wfq_dynlink + test_urcu_wfq_dynlink test_urcu_wfs_dynlink noinst_HEADERS = rcutorture.h if COMPAT_ARCH @@ -42,6 +42,7 @@ URCU_MB_LIB=$(top_builddir)/liburcu-mb.la URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la URCU_BP_LIB=$(top_builddir)/liburcu-bp.la WFQUEUE_LIB=$(top_builddir)/libwfqueue.la +WFSTACK_LIB=$(top_builddir)/libwfstack.la EXTRA_DIST = $(top_srcdir)/tests/api_*.h @@ -160,7 +161,10 @@ test_urcu_wfq_dynlink_SOURCES = test_urcu_wfq.c test_urcu_wfq_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS) test_urcu_wfq_dynlink_LDADD = $(WFQUEUE_LIB) test_urcu_lfs_SOURCES = test_urcu_lfs.c $(URCU_DEFER) -test_urcu_wfs_SOURCES = test_urcu_wfs.c $(URCU_DEFER) +test_urcu_wfs_SOURCES = test_urcu_wfs.c +test_urcu_wfs_dynlink_SOURCES = test_urcu_wfs.c +test_urcu_wfs_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS) +test_urcu_wfs_dynlink_LDADD = $(WFSTACK_LIB) urcutorture.c: api.h diff --git a/urcu/wfstack-static.h b/urcu/wfstack-static.h new file mode 100644 index 0000000..3f44743 --- /dev/null +++ b/urcu/wfstack-static.h @@ -0,0 +1,120 @@ +#ifndef _URCU_WFSTACK_STATIC_H +#define _URCU_WFSTACK_STATIC_H + +/* + * wfstack-static.h + * + * Userspace RCU library - Stack with Wait-Free push, Blocking pop. + * + * TO BE INCLUDED ONLY IN LGPL-COMPATIBLE CODE. See wfstack.h for linking + * dynamically with the userspace rcu library. + * + * Copyright 2010 - Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define WF_STACK_END ((void *)0x1UL) +#define WFS_ADAPT_ATTEMPTS 10 /* Retry if being set */ +#define WFS_WAIT 10 /* Wait 10 ms if being set */ + +void _wfs_node_init(struct wfs_node *node) +{ + node->next = NULL; +} + +void _wfs_init(struct wfs_stack *s) +{ + int ret; + + s->head = WF_STACK_END; + ret = pthread_mutex_init(&s->lock, NULL); + assert(!ret); +} + +void _wfs_push(struct wfs_stack *s, struct wfs_node *node) +{ + struct wfs_node *old_head; + + assert(node->next == NULL); + /* + * uatomic_xchg() implicit memory barrier orders earlier stores to node + * (setting it to NULL) before publication. + */ + old_head = uatomic_xchg(&s->head, node); + /* + * At this point, dequeuers see a NULL node->next, they should busy-wait + * until node->next is set to old_head. + */ + STORE_SHARED(node->next, old_head); +} + +/* + * Returns NULL if stack is empty. + */ +struct wfs_node * +___wfs_pop_blocking(struct wfs_stack *s) +{ + struct wfs_node *head, *next; + int attempt = 0; + +retry: + head = LOAD_SHARED(s->head); + if (head == WF_STACK_END) + return NULL; + /* + * Adaptative busy-looping waiting for push to complete. + */ + while ((next = LOAD_SHARED(head->next)) == NULL) { + if (++attempt >= WFS_ADAPT_ATTEMPTS) { + poll(NULL, 0, WFS_WAIT); /* Wait for 10ms */ + attempt = 0; + } else + cpu_relax(); + } + if (uatomic_cmpxchg(&s->head, head, next) == head) + return head; + else + goto retry; /* Concurrent modification. Retry. */ +} + +struct wfs_node * +_wfs_pop_blocking(struct wfs_stack *s) +{ + struct wfs_node *retnode; + int ret; + + ret = pthread_mutex_lock(&s->lock); + assert(!ret); + retnode = ___wfs_pop_blocking(s); + ret = pthread_mutex_unlock(&s->lock); + assert(!ret); + return retnode; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_WFSTACK_STATIC_H */ diff --git a/urcu/wfstack.h b/urcu/wfstack.h index b3ee2e7..6cb4971 100644 --- a/urcu/wfstack.h +++ b/urcu/wfstack.h @@ -2,7 +2,7 @@ #define _URCU_WFSTACK_H /* - * rcuwfstack.h + * wfstack.h * * Userspace RCU library - Stack with Wait-Free push, Blocking pop. * @@ -31,14 +31,6 @@ extern "C" { #endif -#if (!defined(_GNU_SOURCE) && !defined(_LGPL_SOURCE)) -#error "Dynamic loader LGPL wrappers not implemented yet" -#endif - -#define WF_STACK_END ((void *)0x1UL) -#define WFS_ADAPT_ATTEMPTS 10 /* Retry if being set */ -#define WFS_WAIT 10 /* Wait 10 ms if being set */ - struct wfs_node { struct wfs_node *next; }; @@ -48,79 +40,26 @@ struct wfs_stack { pthread_mutex_t lock; }; -void wfs_node_init(struct wfs_node *node) -{ - node->next = NULL; -} +#ifdef _LGPL_SOURCE -void wfs_init(struct wfs_stack *s) -{ - int ret; +#include - s->head = WF_STACK_END; - ret = pthread_mutex_init(&s->lock, NULL); - assert(!ret); -} +#define wfs_node_init _wfs_node_init +#define wfs_init _wfs_init +#define wfs_push _wfs_push +#define __wfs_pop_blocking ___wfs_pop_blocking +#define wfs_pop_blocking _wfs_pop_blocking -void wfs_push(struct wfs_stack *s, struct wfs_node *node) -{ - struct wfs_node *old_head; +#else /* !_LGPL_SOURCE */ - assert(node->next == NULL); - /* - * uatomic_xchg() implicit memory barrier orders earlier stores to node - * (setting it to NULL) before publication. - */ - old_head = uatomic_xchg(&s->head, node); - /* - * At this point, dequeuers see a NULL node->next, they should busy-wait - * until node->next is set to old_head. - */ - STORE_SHARED(node->next, old_head); -} +extern void wfs_node_init(struct wfs_node *node); +extern void wfs_init(struct wfs_stack *s); +extern void wfs_push(struct wfs_stack *s, struct wfs_node *node); +/* __wfs_pop_blocking: caller ensures mutual exclusion between pops */ +extern struct wfs_node *__wfs_pop_blocking(struct wfs_stack *s); +extern struct wfs_node *wfs_pop_blocking(struct wfs_stack *s); -/* - * Returns NULL if stack is empty. - */ -struct wfs_node * -__wfs_pop_blocking(struct wfs_stack *s) -{ - struct wfs_node *head, *next; - int attempt = 0; - -retry: - head = LOAD_SHARED(s->head); - if (head == WF_STACK_END) - return NULL; - /* - * Adaptative busy-looping waiting for push to complete. - */ - while ((next = LOAD_SHARED(head->next)) == NULL) { - if (++attempt >= WFS_ADAPT_ATTEMPTS) { - poll(NULL, 0, WFS_WAIT); /* Wait for 10ms */ - attempt = 0; - } else - cpu_relax(); - } - if (uatomic_cmpxchg(&s->head, head, next) == head) - return head; - else - goto retry; /* Concurrent modification. Retry. */ -} - -struct wfs_node * -wfs_pop_blocking(struct wfs_stack *s) -{ - struct wfs_node *retnode; - int ret; - - ret = pthread_mutex_lock(&s->lock); - assert(!ret); - retnode = __wfs_pop_blocking(s); - ret = pthread_mutex_unlock(&s->lock); - assert(!ret); - return retnode; -} +#endif /* !_LGPL_SOURCE */ #ifdef __cplusplus } diff --git a/wfstack.c b/wfstack.c new file mode 100644 index 0000000..b72bf80 --- /dev/null +++ b/wfstack.c @@ -0,0 +1,50 @@ +/* + * wfstack.c + * + * Userspace RCU library - Stack with Wait-Free push, Blocking pop. + * + * Copyright 2010 - Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ +#include "urcu/wfstack.h" +#include "urcu/wfstack-static.h" + +void wfs_node_init(struct wfs_node *node) +{ + _wfs_node_init(node); +} + +void wfs_init(struct wfs_stack *s) +{ + _wfs_init(s); +} + +void wfs_push(struct wfs_stack *s, struct wfs_node *node) +{ + _wfs_push(s, node); +} + +struct wfs_node *__wfs_pop_blocking(struct wfs_stack *s) +{ + return ___wfs_pop_blocking(s); +} + +struct wfs_node *wfs_pop_blocking(struct wfs_stack *s) +{ + return _wfs_pop_blocking(s); +} -- 2.34.1