| arch.h | | arch.h | |
| | | | |
| skipping to change at line 32 | | skipping to change at line 32 | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | |
| */ | | */ | |
| | | | |
| #include <urcu/compiler.h> | | #include <urcu/compiler.h> | |
| #include <urcu/config.h> | | #include <urcu/config.h> | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| #define CACHE_LINE_SIZE 128 | | #define CAA_CACHE_LINE_SIZE 128 | |
| | | | |
| #ifdef CONFIG_RCU_HAVE_FENCE | | #ifdef CONFIG_RCU_HAVE_FENCE | |
|
| #define mb() asm volatile("mfence":::"memory") | | #define cmm_mb() asm volatile("mfence":::"memory") | |
| #define rmb() asm volatile("lfence":::"memory") | | #define cmm_rmb() asm volatile("lfence":::"memory") | |
| #define wmb() asm volatile("sfence"::: "memory") | | #define cmm_wmb() asm volatile("sfence"::: "memory") | |
| #else | | #else | |
| /* | | /* | |
|
| * Some non-Intel clones support out of order store. wmb() ceases to be a | | * Some non-Intel clones support out of order store. cmm_wmb() ceases to be
a | |
| * nop for these. | | * nop for these. | |
| */ | | */ | |
|
| #define mb() asm volatile("lock; addl $0,0(%%esp)":::"memory") | | #define cmm_mb() asm volatile("lock; addl $0,0(%%esp)":::"memory") | |
| #define rmb() asm volatile("lock; addl $0,0(%%esp)":::"memory") | | #define cmm_rmb() asm volatile("lock; addl $0,0(%%esp)":::"memory") | |
| #define wmb() asm volatile("lock; addl $0,0(%%esp)"::: "memory") | | #define cmm_wmb() asm volatile("lock; addl $0,0(%%esp)"::: "memory") | |
| #endif | | #endif | |
| | | | |
|
| #define cpu_relax() asm volatile("rep; nop" : : : "memory"); | | #define caa_cpu_relax() asm volatile("rep; nop" : : : "memory"); | |
| | | | |
| #define rdtscll(val) \ | | #define rdtscll(val) \ | |
| do { \ | | do { \ | |
| unsigned int __a, __d; \ | | unsigned int __a, __d; \ | |
| asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \ | | asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \ | |
| (val) = ((unsigned long long)__a) \ | | (val) = ((unsigned long long)__a) \ | |
| | (((unsigned long long)__d) << 32); \ | | | (((unsigned long long)__d) << 32); \ | |
| } while(0) | | } while(0) | |
| | | | |
| typedef unsigned long long cycles_t; | | typedef unsigned long long cycles_t; | |
| | | | |
|
| static inline cycles_t get_cycles(void) | | static inline cycles_t caa_get_cycles(void) | |
| { | | { | |
| cycles_t ret = 0; | | cycles_t ret = 0; | |
| | | | |
| rdtscll(ret); | | rdtscll(ret); | |
| return ret; | | return ret; | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
End of changes. 6 change blocks. |
| 10 lines changed or deleted | | 10 lines changed or added | |
|
| arch_generic.h | | arch_generic.h | |
| | | | |
| skipping to change at line 31 | | skipping to change at line 31 | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | |
| */ | | */ | |
| | | | |
| #include <urcu/compiler.h> | | #include <urcu/compiler.h> | |
| #include <urcu/config.h> | | #include <urcu/config.h> | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| #ifndef CACHE_LINE_SIZE | | #ifndef CAA_CACHE_LINE_SIZE | |
| #define CACHE_LINE_SIZE 64 | | #define CAA_CACHE_LINE_SIZE 64 | |
| #endif | | #endif | |
| | | | |
|
| #if !defined(mc) && !defined(rmc) && !defined(wmc) | | #if !defined(cmm_mc) && !defined(cmm_rmc) && !defined(cmm_wmc) | |
| #define CONFIG_HAVE_MEM_COHERENCY | | #define CONFIG_HAVE_MEM_COHERENCY | |
| /* | | /* | |
|
| * Architectures with cache coherency must _not_ define mc/rmc/wmc. | | * Architectures with cache coherency must _not_ define cmm_mc/cmm_rmc/cmm_
wmc. | |
| * | | * | |
|
| * For them, mc/rmc/wmc are implemented with a * simple compiler barrier; | | * For them, cmm_mc/cmm_rmc/cmm_wmc are implemented with a * simple compile | |
| * in addition, we provide defaults for mb (using GCC builtins) as well as | | r barrier; | |
| * rmb and wmb (defaulting to mb). | | * in addition, we provide defaults for cmm_mb (using GCC builtins) as well | |
| | | as | |
| | | * cmm_rmb and cmm_wmb (defaulting to cmm_mb). | |
| */ | | */ | |
| | | | |
|
| #ifndef mb | | #ifndef cmm_mb | |
| #define mb() __sync_synchronize() | | #define cmm_mb() __sync_synchronize() | |
| #endif | | #endif | |
| | | | |
|
| #ifndef rmb | | #ifndef cmm_rmb | |
| #define rmb() mb() | | #define cmm_rmb() cmm_mb() | |
| #endif | | #endif | |
| | | | |
|
| #ifndef wmb | | #ifndef cmm_wmb | |
| #define wmb() mb() | | #define cmm_wmb() cmm_mb() | |
| #endif | | #endif | |
| | | | |
|
| #define mc() barrier() | | #define cmm_mc() cmm_barrier() | |
| #define rmc() barrier() | | #define cmm_rmc() cmm_barrier() | |
| #define wmc() barrier() | | #define cmm_wmc() cmm_barrier() | |
| #else | | #else | |
| /* | | /* | |
| * Architectures without cache coherency need something like the following: | | * Architectures without cache coherency need something like the following: | |
| * | | * | |
|
| * #define mc() arch_cache_flush() | | * #define cmm_mc() arch_cache_flush() | |
| * #define rmc() arch_cache_flush_read() | | * #define cmm_rmc() arch_cache_flush_read() | |
| * #define wmc() arch_cache_flush_write() | | * #define cmm_wmc() arch_cache_flush_write() | |
| * | | * | |
|
| * Of these, only mc is mandatory. rmc and wmc default to mc. mb/rmb/wmb | | * Of these, only cmm_mc is mandatory. cmm_rmc and cmm_wmc default to cmm_ | |
| * use these definitions by default: | | mc. | |
| | | * cmm_mb/cmm_rmb/cmm_wmb use these definitions by default: | |
| * | | * | |
|
| * #define mb() mc() | | * #define cmm_mb() cmm_mc() | |
| * #define rmb() rmc() | | * #define cmm_rmb() cmm_rmc() | |
| * #define wmb() wmc() | | * #define cmm_wmb() cmm_wmc() | |
| */ | | */ | |
| | | | |
|
| #ifndef mb | | #ifndef cmm_mb | |
| #define mb() mc() | | #define cmm_mb() cmm_mc() | |
| #endif | | #endif | |
| | | | |
|
| #ifndef rmb | | #ifndef cmm_rmb | |
| #define rmb() rmc() | | #define cmm_rmb() cmm_rmc() | |
| #endif | | #endif | |
| | | | |
|
| #ifndef wmb | | #ifndef cmm_wmb | |
| #define wmb() wmc() | | #define cmm_wmb() cmm_wmc() | |
| #endif | | #endif | |
| | | | |
|
| #ifndef rmc | | #ifndef cmm_rmc | |
| #define rmc() mc() | | #define cmm_rmc() cmm_mc() | |
| #endif | | #endif | |
| | | | |
|
| #ifndef wmc | | #ifndef cmm_wmc | |
| #define wmc() mc() | | #define cmm_wmc() cmm_mc() | |
| #endif | | #endif | |
| #endif | | #endif | |
| | | | |
| /* Nop everywhere except on alpha. */ | | /* Nop everywhere except on alpha. */ | |
|
| #ifndef read_barrier_depends | | #ifndef cmm_read_barrier_depends | |
| #define read_barrier_depends() | | #define cmm_read_barrier_depends() | |
| #endif | | #endif | |
| | | | |
| #ifdef CONFIG_RCU_SMP | | #ifdef CONFIG_RCU_SMP | |
|
| #define smp_mb() mb() | | #define cmm_smp_mb() cmm_mb() | |
| #define smp_rmb() rmb() | | #define cmm_smp_rmb() cmm_rmb() | |
| #define smp_wmb() wmb() | | #define cmm_smp_wmb() cmm_wmb() | |
| #define smp_mc() mc() | | #define cmm_smp_mc() cmm_mc() | |
| #define smp_rmc() rmc() | | #define cmm_smp_rmc() cmm_rmc() | |
| #define smp_wmc() wmc() | | #define cmm_smp_wmc() cmm_wmc() | |
| #define smp_read_barrier_depends() read_barrier_depends() | | #define cmm_smp_read_barrier_depends() cmm_read_barrier_depends() | |
| #else | | #else | |
|
| #define smp_mb() barrier() | | #define cmm_smp_mb() cmm_barrier() | |
| #define smp_rmb() barrier() | | #define cmm_smp_rmb() cmm_barrier() | |
| #define smp_wmb() barrier() | | #define cmm_smp_wmb() cmm_barrier() | |
| #define smp_mc() barrier() | | #define cmm_smp_mc() cmm_barrier() | |
| #define smp_rmc() barrier() | | #define cmm_smp_rmc() cmm_barrier() | |
| #define smp_wmc() barrier() | | #define cmm_smp_wmc() cmm_barrier() | |
| #define smp_read_barrier_depends() | | #define cmm_smp_read_barrier_depends() | |
| #endif | | #endif | |
| | | | |
|
| #ifndef cpu_relax | | #ifndef caa_cpu_relax | |
| #define cpu_relax() barrier() | | #define caa_cpu_relax() cmm_barrier() | |
| #endif | | #endif | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_ARCH_GENERIC_H */ | | #endif /* _URCU_ARCH_GENERIC_H */ | |
| | | | |
End of changes. 20 change blocks. |
| 52 lines changed or deleted | | 55 lines changed or added | |
|
| compiler.h | | compiler.h | |
| | | | |
| skipping to change at line 26 | | skipping to change at line 26 | |
| * Permission to modify the code and to distribute modified code is granted
, | | * Permission to modify the code and to distribute modified code is granted
, | |
| * provided the above notices are retained, and a notice that the code was | | * provided the above notices are retained, and a notice that the code was | |
| * modified is included with the above copyright notice. | | * modified is included with the above copyright notice. | |
| */ | | */ | |
| | | | |
| #include <stddef.h> /* for offsetof */ | | #include <stddef.h> /* for offsetof */ | |
| | | | |
| #define likely(x) __builtin_expect(!!(x), 1) | | #define likely(x) __builtin_expect(!!(x), 1) | |
| #define unlikely(x) __builtin_expect(!!(x), 0) | | #define unlikely(x) __builtin_expect(!!(x), 0) | |
| | | | |
|
| #define barrier() asm volatile("" : : : "memory") | | #define cmm_barrier() asm volatile("" : : : "memory") | |
| | | | |
| /* | | /* | |
| * Instruct the compiler to perform only a single access to a variable | | * Instruct the compiler to perform only a single access to a variable | |
| * (prohibits merging and refetching). The compiler is also forbidden to re
order | | * (prohibits merging and refetching). The compiler is also forbidden to re
order | |
|
| * successive instances of ACCESS_ONCE(), but only when the compiler is awa
re of | | * successive instances of CAA_ACCESS_ONCE(), but only when the compiler is
aware of | |
| * particular ordering. Compiler ordering can be ensured, for example, by | | * particular ordering. Compiler ordering can be ensured, for example, by | |
|
| * putting two ACCESS_ONCE() in separate C statements. | | * putting two CAA_ACCESS_ONCE() in separate C statements. | |
| * | | * | |
| * This macro does absolutely -nothing- to prevent the CPU from reordering, | | * This macro does absolutely -nothing- to prevent the CPU from reordering, | |
| * merging, or refetching absolutely anything at any time. Its main intend
ed | | * merging, or refetching absolutely anything at any time. Its main intend
ed | |
| * use is to mediate communication between process-level code and irq/NMI | | * use is to mediate communication between process-level code and irq/NMI | |
| * handlers, all running on the same CPU. | | * handlers, all running on the same CPU. | |
| */ | | */ | |
|
| #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) | | #define CAA_ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) | |
| | | | |
| #ifndef max | | #ifndef max | |
| #define max(a,b) ((a)>(b)?(a):(b)) | | #define max(a,b) ((a)>(b)?(a):(b)) | |
| #endif | | #endif | |
| | | | |
| #ifndef min | | #ifndef min | |
| #define min(a,b) ((a)<(b)?(a):(b)) | | #define min(a,b) ((a)<(b)?(a):(b)) | |
| #endif | | #endif | |
| | | | |
| #if defined(__SIZEOF_LONG__) | | #if defined(__SIZEOF_LONG__) | |
|
| #define BITS_PER_LONG (__SIZEOF_LONG__ * 8) | | #define CAA_BITS_PER_LONG (__SIZEOF_LONG__ * 8) | |
| #elif defined(_LP64) | | #elif defined(_LP64) | |
|
| #define BITS_PER_LONG 64 | | #define CAA_BITS_PER_LONG 64 | |
| #else | | #else | |
|
| #define BITS_PER_LONG 32 | | #define CAA_BITS_PER_LONG 32 | |
| #endif | | #endif | |
| | | | |
|
| #define container_of(ptr, type, member)
\ | | #define caa_container_of(ptr, type, member)
\ | |
| ({ \ | | ({ \ | |
| const typeof(((type *)NULL)->member) * __ptr = (ptr); \ | | const typeof(((type *)NULL)->member) * __ptr = (ptr); \ | |
| (type *)((char *)__ptr - offsetof(type, member)); \ | | (type *)((char *)__ptr - offsetof(type, member)); \ | |
| }) | | }) | |
| | | | |
| #endif /* _URCU_COMPILER_H */ | | #endif /* _URCU_COMPILER_H */ | |
| | | | |
End of changes. 8 change blocks. |
| 8 lines changed or deleted | | 8 lines changed or added | |
|
| hlist.h | | hlist.h | |
| | | | |
| skipping to change at line 19 | | skipping to change at line 19 | |
| * | | * | |
| * Author: Jan Blunck <jblunck@suse.de> | | * Author: Jan Blunck <jblunck@suse.de> | |
| * | | * | |
| * Copyright (C) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | | * Copyright (C) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
| * | | * | |
| * This program is free software; you can redistribute it and/or modify it | | * This program is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU Lesser General Public License version 2.1 as | | * under the terms of the GNU Lesser General Public License version 2.1 as | |
| * published by the Free Software Foundation. | | * published by the Free Software Foundation. | |
| */ | | */ | |
| | | | |
|
| struct hlist_head | | struct cds_hlist_head | |
| { | | { | |
|
| struct hlist_node *next; | | struct cds_hlist_node *next; | |
| }; | | }; | |
| | | | |
|
| struct hlist_node | | struct cds_hlist_node | |
| { | | { | |
|
| struct hlist_node *next; | | struct cds_hlist_node *next; | |
| struct hlist_node *prev; | | struct cds_hlist_node *prev; | |
| }; | | }; | |
| | | | |
| /* Initialize a new list head. */ | | /* Initialize a new list head. */ | |
|
| static inline void INIT_HLIST_HEAD(struct hlist_head *ptr) | | static inline void CDS_INIT_HLIST_HEAD(struct cds_hlist_head *ptr) | |
| { | | { | |
| ptr->next = NULL; | | ptr->next = NULL; | |
| } | | } | |
| | | | |
| /* Get typed element from list at a given position. */ | | /* Get typed element from list at a given position. */ | |
|
| #define hlist_entry(ptr, type, member) \ | | #define cds_hlist_entry(ptr, type, member)
\ | |
| ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))
) | | ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))
) | |
| | | | |
| /* Add new element at the head of the list. */ | | /* Add new element at the head of the list. */ | |
|
| static inline void hlist_add_head (struct hlist_node *newp, | | static inline void cds_hlist_add_head (struct cds_hlist_node *newp, | |
| struct hlist_head *head) | | struct cds_hlist_head *head) | |
| { | | { | |
| if (head->next) | | if (head->next) | |
| head->next->prev = newp; | | head->next->prev = newp; | |
| | | | |
| newp->next = head->next; | | newp->next = head->next; | |
|
| newp->prev = (struct hlist_node *)head; | | newp->prev = (struct cds_hlist_node *)head; | |
| head->next = newp; | | head->next = newp; | |
| } | | } | |
| | | | |
| /* Remove element from list. */ | | /* Remove element from list. */ | |
|
| static inline void hlist_del (struct hlist_node *elem) | | static inline void cds_hlist_del (struct cds_hlist_node *elem) | |
| { | | { | |
| if (elem->next) | | if (elem->next) | |
| elem->next->prev = elem->prev; | | elem->next->prev = elem->prev; | |
| | | | |
| elem->prev->next = elem->next; | | elem->prev->next = elem->next; | |
| } | | } | |
| | | | |
|
| #define hlist_for_each_entry(entry, pos, head, member) \ | | #define cds_hlist_for_each_entry(entry, pos, head, member)
\ | |
| for (pos = (head)->next, \ | | for (pos = (head)->next, \ | |
|
| entry = hlist_entry(pos, typeof(*entry), member); \ | | entry = cds_hlist_entry(pos, typeof(*entry), member);
\ | |
| pos != NULL; \ | | pos != NULL; \ | |
| pos = pos->next, \ | | pos = pos->next, \ | |
|
| entry = hlist_entry(pos, typeof(*entry), member)) | | entry = cds_hlist_entry(pos, typeof(*entry), member)) | |
| | | | |
|
| #define hlist_for_each_entry_safe(entry, pos, p, head, member) \ | | #define cds_hlist_for_each_entry_safe(entry, pos, p, head, member)
\ | |
| for (pos = (head)->next, \ | | for (pos = (head)->next, \ | |
|
| entry = hlist_entry(pos, typeof(*entry), member); \ | | entry = cds_hlist_entry(pos, typeof(*entry), member);
\ | |
| (pos != NULL) && ({ p = pos->next; 1;}); \ | | (pos != NULL) && ({ p = pos->next; 1;}); \ | |
| pos = p, \ | | pos = p, \ | |
|
| entry = hlist_entry(pos, typeof(*entry), member)) | | entry = cds_hlist_entry(pos, typeof(*entry), member)) | |
| | | | |
| #endif /* _KCOMPAT_HLIST_H */ | | #endif /* _KCOMPAT_HLIST_H */ | |
| | | | |
End of changes. 15 change blocks. |
| 17 lines changed or deleted | | 17 lines changed or added | |
|
| list.h | | list.h | |
| | | | |
| skipping to change at line 28 | | skipping to change at line 28 | |
| 02111-1307 USA. */ | | 02111-1307 USA. */ | |
| | | | |
| #ifndef _LIST_H | | #ifndef _LIST_H | |
| #define _LIST_H 1 | | #define _LIST_H 1 | |
| | | | |
| /* The definitions of this file are adopted from those which can be | | /* The definitions of this file are adopted from those which can be | |
| found in the Linux kernel headers to enable people familiar with | | found in the Linux kernel headers to enable people familiar with | |
| the latter find their way in these sources as well. */ | | the latter find their way in these sources as well. */ | |
| | | | |
| /* Basic type for the double-link list. */ | | /* Basic type for the double-link list. */ | |
|
| typedef struct list_head | | typedef struct cds_list_head | |
| { | | { | |
|
| struct list_head *next; | | struct cds_list_head *next; | |
| struct list_head *prev; | | struct cds_list_head *prev; | |
| } list_t; | | } list_t; | |
| | | | |
| /* Define a variable with the head and tail of the list. */ | | /* Define a variable with the head and tail of the list. */ | |
|
| #define LIST_HEAD(name) \ | | #define CDS_LIST_HEAD(name) \ | |
| list_t name = { &(name), &(name) } | | list_t name = { &(name), &(name) } | |
| | | | |
| /* Initialize a new list head. */ | | /* Initialize a new list head. */ | |
|
| #define INIT_LIST_HEAD(ptr) \ | | #define CDS_INIT_LIST_HEAD(ptr) \ | |
| (ptr)->next = (ptr)->prev = (ptr) | | (ptr)->next = (ptr)->prev = (ptr) | |
| | | | |
|
| #define LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) } | | #define CDS_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) } | |
| | | | |
| /* Add new element at the head of the list. */ | | /* Add new element at the head of the list. */ | |
| static inline void | | static inline void | |
|
| list_add (list_t *newp, list_t *head) | | cds_list_add (list_t *newp, list_t *head) | |
| { | | { | |
| head->next->prev = newp; | | head->next->prev = newp; | |
| newp->next = head->next; | | newp->next = head->next; | |
| newp->prev = head; | | newp->prev = head; | |
| head->next = newp; | | head->next = newp; | |
| } | | } | |
| | | | |
| /* Add new element at the tail of the list. */ | | /* Add new element at the tail of the list. */ | |
| static inline void | | static inline void | |
|
| list_add_tail (list_t *newp, list_t *head) | | cds_list_add_tail (list_t *newp, list_t *head) | |
| { | | { | |
| head->prev->next = newp; | | head->prev->next = newp; | |
| newp->next = head; | | newp->next = head; | |
| newp->prev = head->prev; | | newp->prev = head->prev; | |
| head->prev = newp; | | head->prev = newp; | |
| } | | } | |
| | | | |
| /* Remove element from list. */ | | /* Remove element from list. */ | |
| static inline void | | static inline void | |
|
| __list_del (list_t *prev, list_t *next) | | __cds_list_del (list_t *prev, list_t *next) | |
| { | | { | |
| next->prev = prev; | | next->prev = prev; | |
| prev->next = next; | | prev->next = next; | |
| } | | } | |
| | | | |
| /* Remove element from list. */ | | /* Remove element from list. */ | |
| static inline void | | static inline void | |
|
| list_del (list_t *elem) | | cds_list_del (list_t *elem) | |
| { | | { | |
|
| __list_del (elem->prev, elem->next); | | __cds_list_del (elem->prev, elem->next); | |
| } | | } | |
| | | | |
| /* delete from list, add to another list as head */ | | /* delete from list, add to another list as head */ | |
| static inline void | | static inline void | |
|
| list_move (list_t *elem, list_t *head) | | cds_list_move (list_t *elem, list_t *head) | |
| { | | { | |
|
| __list_del (elem->prev, elem->next); | | __cds_list_del (elem->prev, elem->next); | |
| list_add (elem, head); | | cds_list_add (elem, head); | |
| } | | } | |
| | | | |
| /* replace an old entry. | | /* replace an old entry. | |
| */ | | */ | |
| static inline void | | static inline void | |
|
| list_replace(list_t *old, list_t *_new) | | cds_list_replace(list_t *old, list_t *_new) | |
| { | | { | |
| _new->next = old->next; | | _new->next = old->next; | |
| _new->prev = old->prev; | | _new->prev = old->prev; | |
| _new->prev->next = _new; | | _new->prev->next = _new; | |
| _new->next->prev = _new; | | _new->next->prev = _new; | |
| } | | } | |
| | | | |
| /* Join two lists. */ | | /* Join two lists. */ | |
| static inline void | | static inline void | |
|
| list_splice (list_t *add, list_t *head) | | cds_list_splice (list_t *add, list_t *head) | |
| { | | { | |
| /* Do nothing if the list which gets added is empty. */ | | /* Do nothing if the list which gets added is empty. */ | |
| if (add != add->next) | | if (add != add->next) | |
| { | | { | |
| add->next->prev = head; | | add->next->prev = head; | |
| add->prev->next = head->next; | | add->prev->next = head->next; | |
| head->next->prev = add->prev; | | head->next->prev = add->prev; | |
| head->next = add->next; | | head->next = add->next; | |
| } | | } | |
| } | | } | |
| | | | |
| /* Get typed element from list at a given position. */ | | /* Get typed element from list at a given position. */ | |
|
| #define list_entry(ptr, type, member) \ | | #define cds_list_entry(ptr, type, member) \ | |
| ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) | | ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) | |
| | | | |
| /* Iterate forward over the elements of the list. */ | | /* Iterate forward over the elements of the list. */ | |
|
| #define list_for_each(pos, head) \ | | #define cds_list_for_each(pos, head) \ | |
| for (pos = (head)->next; pos != (head); pos = pos->next) | | for (pos = (head)->next; pos != (head); pos = pos->next) | |
| | | | |
| /* Iterate forward over the elements of the list. */ | | /* Iterate forward over the elements of the list. */ | |
|
| #define list_for_each_prev(pos, head) \ | | #define cds_list_for_each_prev(pos, head) \ | |
| for (pos = (head)->prev; pos != (head); pos = pos->prev) | | for (pos = (head)->prev; pos != (head); pos = pos->prev) | |
| | | | |
| /* Iterate backwards over the elements list. The list elements can be | | /* Iterate backwards over the elements list. The list elements can be | |
| removed from the list while doing this. */ | | removed from the list while doing this. */ | |
|
| #define list_for_each_prev_safe(pos, p, head) \ | | #define cds_list_for_each_prev_safe(pos, p, head) \ | |
| for (pos = (head)->prev, p = pos->prev; \ | | for (pos = (head)->prev, p = pos->prev; \ | |
| pos != (head); \ | | pos != (head); \ | |
| pos = p, p = pos->prev) | | pos = p, p = pos->prev) | |
| | | | |
|
| #define list_for_each_entry(pos, head, member) \ | | #define cds_list_for_each_entry(pos, head, member) | |
| for (pos = list_entry((head)->next, typeof(*pos), member); \ | | \ | |
| | | for (pos = cds_list_entry((head)->next, typeof(*pos), member); \ | |
| &pos->member != (head); \ | | &pos->member != (head); \ | |
|
| pos = list_entry(pos->member.next, typeof(*pos), member)) | | pos = cds_list_entry(pos->member.next, typeof(*pos), member)) | |
| | | | |
|
| #define list_for_each_entry_reverse(pos, head, member) \ | | #define cds_list_for_each_entry_reverse(pos, head, member) | |
| for (pos = list_entry((head)->prev, typeof(*pos), member); \ | | \ | |
| | | for (pos = cds_list_entry((head)->prev, typeof(*pos), member); \ | |
| &pos->member != (head); \ | | &pos->member != (head); \ | |
|
| pos = list_entry(pos->member.prev, typeof(*pos), member)) | | pos = cds_list_entry(pos->member.prev, typeof(*pos), member)) | |
| | | | |
|
| #define list_for_each_entry_safe(pos, p, head, member) \ | | #define cds_list_for_each_entry_safe(pos, p, head, member) | |
| for (pos = list_entry((head)->next, typeof(*pos), member), \ | | \ | |
| p = list_entry(pos->member.next,typeof(*pos), member); | | for (pos = cds_list_entry((head)->next, typeof(*pos), member), \ | |
| \ | | p = cds_list_entry(pos->member.next,typeof(*pos), membe | |
| | | r); \ | |
| &pos->member != (head); \ | | &pos->member != (head); \ | |
|
| pos = p, p = list_entry(pos->member.next, typeof(*pos), member)
) | | pos = p, p = cds_list_entry(pos->member.next, typeof(*pos), mem
ber)) | |
| | | | |
|
| static inline int list_empty(list_t *head) | | static inline int cds_list_empty(list_t *head) | |
| { | | { | |
| return head == head->next; | | return head == head->next; | |
| } | | } | |
| | | | |
|
| static inline void list_replace_init(list_t *old, | | static inline void cds_list_replace_init(list_t *old, | |
| list_t *_new) | | list_t *_new) | |
| { | | { | |
| list_t *head = old->next; | | list_t *head = old->next; | |
|
| list_del(old); | | cds_list_del(old); | |
| list_add_tail(_new, head); | | cds_list_add_tail(_new, head); | |
| INIT_LIST_HEAD(old); | | CDS_INIT_LIST_HEAD(old); | |
| } | | } | |
| | | | |
| #endif /* list.h */ | | #endif /* list.h */ | |
| | | | |
End of changes. 27 change blocks. |
| 36 lines changed or deleted | | 39 lines changed or added | |
|
| rcuhlist.h | | rcuhlist.h | |
| | | | |
| skipping to change at line 33 | | skipping to change at line 33 | |
| | | | |
| #ifndef _URCU_RCUHLIST_H | | #ifndef _URCU_RCUHLIST_H | |
| #define _URCU_RCUHLIST_H | | #define _URCU_RCUHLIST_H | |
| | | | |
| #include <urcu/hlist.h> | | #include <urcu/hlist.h> | |
| #include <urcu/arch.h> | | #include <urcu/arch.h> | |
| #include <urcu-pointer.h> | | #include <urcu-pointer.h> | |
| | | | |
| /* Add new element at the head of the list. | | /* Add new element at the head of the list. | |
| */ | | */ | |
|
| static inline void hlist_add_head_rcu(struct hlist_node *newp, | | static inline void cds_hlist_add_head_rcu(struct cds_hlist_node *newp, | |
| struct hlist_head *head) | | struct cds_hlist_head *head) | |
| { | | { | |
| newp->next = head->next; | | newp->next = head->next; | |
|
| newp->prev = (struct hlist_node *)head; | | newp->prev = (struct cds_hlist_node *)head; | |
| smp_wmb(); | | cmm_smp_wmb(); | |
| if (head->next) | | if (head->next) | |
| head->next->prev = newp; | | head->next->prev = newp; | |
| head->next = newp; | | head->next = newp; | |
| } | | } | |
| | | | |
| /* Remove element from list. */ | | /* Remove element from list. */ | |
|
| static inline void hlist_del_rcu(struct hlist_node *elem) | | static inline void cds_hlist_del_rcu(struct cds_hlist_node *elem) | |
| { | | { | |
| if (elem->next) | | if (elem->next) | |
| elem->next->prev = elem->prev; | | elem->next->prev = elem->prev; | |
| elem->prev->next = elem->next; | | elem->prev->next = elem->next; | |
| } | | } | |
| | | | |
| /* Iterate through elements of the list. | | /* Iterate through elements of the list. | |
| * This must be done while rcu_read_lock() is held. | | * This must be done while rcu_read_lock() is held. | |
| */ | | */ | |
| | | | |
|
| #define hlist_for_each_entry_rcu(entry, pos, head, member) \ | | #define cds_hlist_for_each_entry_rcu(entry, pos, head, member) \ | |
| for (pos = rcu_dereference((head)->next), \ | | for (pos = rcu_dereference((head)->next), \ | |
|
| entry = hlist_entry(pos, typeof(*entry), member); \ | | entry = cds_hlist_entry(pos, typeof(*entry), member);
\ | |
| pos != NULL; \ | | pos != NULL; \ | |
| pos = rcu_dereference(pos->next), \ | | pos = rcu_dereference(pos->next), \ | |
|
| entry = hlist_entry(pos, typeof(*entry), member)) | | entry = cds_hlist_entry(pos, typeof(*entry), member)) | |
| | | | |
| #endif /* _URCU_RCUHLIST_H */ | | #endif /* _URCU_RCUHLIST_H */ | |
| | | | |
End of changes. 6 change blocks. |
| 8 lines changed or deleted | | 8 lines changed or added | |
|
| rculfqueue-static.h | | rculfqueue-static.h | |
| | | | |
| skipping to change at line 50 | | skipping to change at line 50 | |
| * hold a RCU read lock to deal with cmpxchg ABA problem. This implementati
on | | * hold a RCU read lock to deal with cmpxchg ABA problem. This implementati
on | |
| * keeps a dummy head node to ensure we can always update the queue lockles
sly. | | * keeps a dummy head node to ensure we can always update the queue lockles
sly. | |
| * Given that this is a queue, the dummy head node must always advance as w
e | | * Given that this is a queue, the dummy head node must always advance as w
e | |
| * dequeue entries. Therefore, we keep a reference count on each entry we a
re | | * dequeue entries. Therefore, we keep a reference count on each entry we a
re | |
| * dequeueing, so they can be kept as dummy head node until the next dequeu
e, at | | * dequeueing, so they can be kept as dummy head node until the next dequeu
e, at | |
| * which point their reference count will be decremented. | | * which point their reference count will be decremented. | |
| */ | | */ | |
| | | | |
| #define URCU_LFQ_PERMANENT_REF 128 | | #define URCU_LFQ_PERMANENT_REF 128 | |
| | | | |
|
| void _rcu_lfq_node_init(struct rcu_lfq_node *node) | | void _cds_lfq_node_init_rcu(struct cds_lfq_node_rcu *node) | |
| { | | { | |
| node->next = NULL; | | node->next = NULL; | |
| urcu_ref_init(&node->ref); | | urcu_ref_init(&node->ref); | |
| } | | } | |
| | | | |
|
| void _rcu_lfq_init(struct rcu_lfq_queue *q) | | void _cds_lfq_init_rcu(struct cds_lfq_queue_rcu *q) | |
| { | | { | |
|
| _rcu_lfq_node_init(&q->init); | | _cds_lfq_node_init_rcu(&q->init); | |
| /* Make sure the initial node is never freed. */ | | /* Make sure the initial node is never freed. */ | |
| urcu_ref_set(&q->init.ref, URCU_LFQ_PERMANENT_REF); | | urcu_ref_set(&q->init.ref, URCU_LFQ_PERMANENT_REF); | |
| q->head = q->tail = &q->init; | | q->head = q->tail = &q->init; | |
| } | | } | |
| | | | |
|
| void _rcu_lfq_enqueue(struct rcu_lfq_queue *q, struct rcu_lfq_node *node) | | void _cds_lfq_enqueue_rcu(struct cds_lfq_queue_rcu *q, struct cds_lfq_node_
rcu *node) | |
| { | | { | |
| urcu_ref_get(&node->ref); | | urcu_ref_get(&node->ref); | |
| | | | |
| /* | | /* | |
| * uatomic_cmpxchg() implicit memory barrier orders earlier stores t
o | | * uatomic_cmpxchg() implicit memory barrier orders earlier stores t
o | |
| * node before publication. | | * node before publication. | |
| */ | | */ | |
| | | | |
| for (;;) { | | for (;;) { | |
|
| struct rcu_lfq_node *tail, *next; | | struct cds_lfq_node_rcu *tail, *next; | |
| | | | |
| rcu_read_lock(); | | rcu_read_lock(); | |
| tail = rcu_dereference(q->tail); | | tail = rcu_dereference(q->tail); | |
| /* | | /* | |
| * Typically expect tail->next to be NULL. | | * Typically expect tail->next to be NULL. | |
| */ | | */ | |
| next = uatomic_cmpxchg(&tail->next, NULL, node); | | next = uatomic_cmpxchg(&tail->next, NULL, node); | |
| if (next == NULL) { | | if (next == NULL) { | |
| /* | | /* | |
| * Tail was at the end of queue, we successfully | | * Tail was at the end of queue, we successfully | |
| | | | |
| skipping to change at line 108 | | skipping to change at line 108 | |
| rcu_read_unlock(); | | rcu_read_unlock(); | |
| continue; | | continue; | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| /* | | /* | |
| * The entry returned by dequeue must be taken care of by doing a urcu_ref_
put, | | * The entry returned by dequeue must be taken care of by doing a urcu_ref_
put, | |
| * which calls the release primitive when the reference count drops to zero
. A | | * which calls the release primitive when the reference count drops to zero
. A | |
| * grace period must be waited after execution of the release callback befo
re | | * grace period must be waited after execution of the release callback befo
re | |
|
| * performing the actual memory reclamation or modifying the rcu_lfq_node | | * performing the actual memory reclamation or modifying the cds_lfq_node_r
cu | |
| * structure. | | * structure. | |
| * In other words, the entry lfq node returned by dequeue must not be | | * In other words, the entry lfq node returned by dequeue must not be | |
| * modified/re-used/freed until the reference count reaches zero and a grac
e | | * modified/re-used/freed until the reference count reaches zero and a grac
e | |
| * period has elapsed (after the refcount reached 0). | | * period has elapsed (after the refcount reached 0). | |
| */ | | */ | |
|
| struct rcu_lfq_node * | | struct cds_lfq_node_rcu * | |
| _rcu_lfq_dequeue(struct rcu_lfq_queue *q, void (*release)(struct urcu_ref * | | _cds_lfq_dequeue_rcu(struct cds_lfq_queue_rcu *q, void (*release)(struct ur | |
| )) | | cu_ref *)) | |
| { | | { | |
| for (;;) { | | for (;;) { | |
|
| struct rcu_lfq_node *head, *next; | | struct cds_lfq_node_rcu *head, *next; | |
| | | | |
| rcu_read_lock(); | | rcu_read_lock(); | |
| head = rcu_dereference(q->head); | | head = rcu_dereference(q->head); | |
| next = rcu_dereference(head->next); | | next = rcu_dereference(head->next); | |
| if (next) { | | if (next) { | |
| if (uatomic_cmpxchg(&q->head, head, next) == head) { | | if (uatomic_cmpxchg(&q->head, head, next) == head) { | |
| rcu_read_unlock(); | | rcu_read_unlock(); | |
| urcu_ref_put(&head->ref, release); | | urcu_ref_put(&head->ref, release); | |
| return next; | | return next; | |
| } else { | | } else { | |
| | | | |
End of changes. 8 change blocks. |
| 10 lines changed or deleted | | 10 lines changed or added | |
|
| rculfqueue.h | | rculfqueue.h | |
| | | | |
| skipping to change at line 43 | | skipping to change at line 43 | |
| /* | | /* | |
| * Lock-free RCU queue using reference counting. Enqueue and dequeue operat
ions | | * Lock-free RCU queue using reference counting. Enqueue and dequeue operat
ions | |
| * hold a RCU read lock to deal with cmpxchg ABA problem. This implementati
on | | * hold a RCU read lock to deal with cmpxchg ABA problem. This implementati
on | |
| * keeps a dummy head node to ensure we can always update the queue lockles
sly. | | * keeps a dummy head node to ensure we can always update the queue lockles
sly. | |
| * Given that this is a queue, the dummy head node must always advance as w
e | | * Given that this is a queue, the dummy head node must always advance as w
e | |
| * dequeue entries. Therefore, we keep a reference count on each entry we a
re | | * dequeue entries. Therefore, we keep a reference count on each entry we a
re | |
| * dequeueing, so they can be kept as dummy head node until the next dequeu
e, at | | * dequeueing, so they can be kept as dummy head node until the next dequeu
e, at | |
| * which point their reference count will be decremented. | | * which point their reference count will be decremented. | |
| */ | | */ | |
| | | | |
|
| struct rcu_lfq_node { | | struct cds_lfq_node_rcu { | |
| struct rcu_lfq_node *next; | | struct cds_lfq_node_rcu *next; | |
| struct urcu_ref ref; | | struct urcu_ref ref; | |
| }; | | }; | |
| | | | |
|
| struct rcu_lfq_queue { | | struct cds_lfq_queue_rcu { | |
| struct rcu_lfq_node *head, *tail; | | struct cds_lfq_node_rcu *head, *tail; | |
| struct rcu_lfq_node init; /* Dummy initialization node */ | | struct cds_lfq_node_rcu init; /* Dummy initialization node */ | |
| }; | | }; | |
| | | | |
| #ifdef _LGPL_SOURCE | | #ifdef _LGPL_SOURCE | |
| | | | |
| #include <urcu/rculfqueue-static.h> | | #include <urcu/rculfqueue-static.h> | |
| | | | |
|
| #define rcu_lfq_node_init _rcu_lfq_node_init | | #define cds_lfq_node_init_rcu _cds_lfq_node_init_rcu | |
| #define rcu_lfq_init _rcu_lfq_init | | #define cds_lfq_init_rcu _cds_lfq_init_rcu | |
| #define rcu_lfq_enqueue _rcu_lfq_enqueue | | #define cds_lfq_enqueue_rcu _cds_lfq_enqueue_rcu | |
| #define rcu_lfq_dequeue _rcu_lfq_dequeue | | #define cds_lfq_dequeue_rcu _cds_lfq_dequeue_rcu | |
| | | | |
| #else /* !_LGPL_SOURCE */ | | #else /* !_LGPL_SOURCE */ | |
| | | | |
|
| extern void rcu_lfq_node_init(struct rcu_lfq_node *node); | | extern void cds_lfq_node_init_rcu(struct cds_lfq_node_rcu *node); | |
| extern void rcu_lfq_init(struct rcu_lfq_queue *q); | | extern void cds_lfq_init_rcu(struct cds_lfq_queue_rcu *q); | |
| extern void rcu_lfq_enqueue(struct rcu_lfq_queue *q, struct rcu_lfq_node *n | | extern void cds_lfq_enqueue_rcu(struct cds_lfq_queue_rcu *q, struct cds_lfq | |
| ode); | | _node_rcu *node); | |
| | | | |
| /* | | /* | |
| * The entry returned by dequeue must be taken care of by doing a urcu_ref_
put, | | * The entry returned by dequeue must be taken care of by doing a urcu_ref_
put, | |
| * which calls the release primitive when the reference count drops to zero
. A | | * which calls the release primitive when the reference count drops to zero
. A | |
| * grace period must be waited after execution of the release callback befo
re | | * grace period must be waited after execution of the release callback befo
re | |
|
| * performing the actual memory reclamation or modifying the rcu_lfq_node | | * performing the actual memory reclamation or modifying the cds_lfq_node_r
cu | |
| * structure. | | * structure. | |
| * In other words, the entry lfq node returned by dequeue must not be | | * In other words, the entry lfq node returned by dequeue must not be | |
| * modified/re-used/freed until the reference count reaches zero and a grac
e | | * modified/re-used/freed until the reference count reaches zero and a grac
e | |
| * period has elapsed (after the refcount reached 0). | | * period has elapsed (after the refcount reached 0). | |
| */ | | */ | |
|
| extern struct rcu_lfq_node * | | extern struct cds_lfq_node_rcu * | |
| rcu_lfq_dequeue(struct rcu_lfq_queue *q, void (*release)(struct urcu_ref *) | | cds_lfq_dequeue_rcu(struct cds_lfq_queue_rcu *q, void (*release)(struct urc | |
| ); | | u_ref *)); | |
| | | | |
| #endif /* !_LGPL_SOURCE */ | | #endif /* !_LGPL_SOURCE */ | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_RCULFQUEUE_H */ | | #endif /* _URCU_RCULFQUEUE_H */ | |
| | | | |
End of changes. 6 change blocks. |
| 17 lines changed or deleted | | 17 lines changed or added | |
|
| rculfstack-static.h | | rculfstack-static.h | |
| | | | |
| skipping to change at line 36 | | skipping to change at line 36 | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | |
| */ | | */ | |
| | | | |
| #include <urcu/uatomic_arch.h> | | #include <urcu/uatomic_arch.h> | |
| /* A urcu implementation header should be already included. */ | | /* A urcu implementation header should be already included. */ | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| void _rcu_lfs_node_init(struct rcu_lfs_node *node) | | void _cds_lfs_node_init_rcu(struct cds_lfs_node_rcu *node) | |
| { | | { | |
| } | | } | |
| | | | |
|
| void _rcu_lfs_init(struct rcu_lfs_stack *s) | | void _cds_lfs_init_rcu(struct cds_lfs_stack_rcu *s) | |
| { | | { | |
| s->head = NULL; | | s->head = NULL; | |
| } | | } | |
| | | | |
|
| void _rcu_lfs_push(struct rcu_lfs_stack *s, struct rcu_lfs_node *node) | | void _cds_lfs_push_rcu(struct cds_lfs_stack_rcu *s, struct cds_lfs_node_rcu
*node) | |
| { | | { | |
|
| struct rcu_lfs_node *head = NULL; | | struct cds_lfs_node_rcu *head = NULL; | |
| | | | |
| for (;;) { | | for (;;) { | |
|
| struct rcu_lfs_node *old_head = head; | | struct cds_lfs_node_rcu *old_head = head; | |
| | | | |
| node->next = head; | | node->next = head; | |
| /* | | /* | |
| * uatomic_cmpxchg() implicit memory barrier orders earlier | | * uatomic_cmpxchg() implicit memory barrier orders earlier | |
| * stores to node before publication. | | * stores to node before publication. | |
| */ | | */ | |
| head = uatomic_cmpxchg(&s->head, old_head, node); | | head = uatomic_cmpxchg(&s->head, old_head, node); | |
| if (old_head == head) | | if (old_head == head) | |
| break; | | break; | |
| } | | } | |
| } | | } | |
| | | | |
| /* | | /* | |
| * The caller must wait for a grace period to pass before freeing the retur
ned | | * The caller must wait for a grace period to pass before freeing the retur
ned | |
|
| * node or modifying the rcu_lfs_node structure. | | * node or modifying the cds_lfs_node_rcu structure. | |
| * Returns NULL if stack is empty. | | * Returns NULL if stack is empty. | |
| */ | | */ | |
|
| struct rcu_lfs_node * | | struct cds_lfs_node_rcu * | |
| _rcu_lfs_pop(struct rcu_lfs_stack *s) | | _cds_lfs_pop_rcu(struct cds_lfs_stack_rcu *s) | |
| { | | { | |
| for (;;) { | | for (;;) { | |
|
| struct rcu_lfs_node *head; | | struct cds_lfs_node_rcu *head; | |
| | | | |
| rcu_read_lock(); | | rcu_read_lock(); | |
| head = rcu_dereference(s->head); | | head = rcu_dereference(s->head); | |
| if (head) { | | if (head) { | |
|
| struct rcu_lfs_node *next = rcu_dereference(head->ne
xt); | | struct cds_lfs_node_rcu *next = rcu_dereference(head
->next); | |
| | | | |
| if (uatomic_cmpxchg(&s->head, head, next) == head) { | | if (uatomic_cmpxchg(&s->head, head, next) == head) { | |
| rcu_read_unlock(); | | rcu_read_unlock(); | |
| return head; | | return head; | |
| } else { | | } else { | |
| /* Concurrent modification. Retry. */ | | /* Concurrent modification. Retry. */ | |
| rcu_read_unlock(); | | rcu_read_unlock(); | |
| continue; | | continue; | |
| } | | } | |
| } else { | | } else { | |
| | | | |
End of changes. 9 change blocks. |
| 10 lines changed or deleted | | 10 lines changed or added | |
|
| rculfstack.h | | rculfstack.h | |
| | | | |
| skipping to change at line 30 | | skipping to change at line 30 | |
| * | | * | |
| * You should have received a copy of the GNU Lesser General Public | | * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | | * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | |
| */ | | */ | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| struct rcu_lfs_node { | | struct cds_lfs_node_rcu { | |
| struct rcu_lfs_node *next; | | struct cds_lfs_node_rcu *next; | |
| }; | | }; | |
| | | | |
|
| struct rcu_lfs_stack { | | struct cds_lfs_stack_rcu { | |
| struct rcu_lfs_node *head; | | struct cds_lfs_node_rcu *head; | |
| }; | | }; | |
| | | | |
| #ifdef _LGPL_SOURCE | | #ifdef _LGPL_SOURCE | |
| | | | |
| #include <urcu/rculfstack-static.h> | | #include <urcu/rculfstack-static.h> | |
| | | | |
|
| #define rcu_lfs_node_init _rcu_lfs_node_init | | #define cds_lfs_node_init_rcu _cds_lfs_node_init_rcu | |
| #define rcu_lfs_init _rcu_lfs_init | | #define cds_lfs_init_rcu _cds_lfs_init_rcu | |
| #define rcu_lfs_push _rcu_lfs_push | | #define cds_lfs_push_rcu _cds_lfs_push_rcu | |
| #define rcu_lfs_pop _rcu_lfs_pop | | #define cds_lfs_pop_rcu _cds_lfs_pop_rcu | |
| | | | |
| #else /* !_LGPL_SOURCE */ | | #else /* !_LGPL_SOURCE */ | |
| | | | |
|
| extern void rcu_lfs_node_init(struct rcu_lfs_node *node); | | extern void cds_lfs_node_init_rcu(struct cds_lfs_node_rcu *node); | |
| extern void rcu_lfs_init(struct rcu_lfs_stack *s); | | extern void cds_lfs_init_rcu(struct cds_lfs_stack_rcu *s); | |
| extern void rcu_lfs_push(struct rcu_lfs_stack *s, struct rcu_lfs_node *node | | extern void cds_lfs_push_rcu(struct cds_lfs_stack_rcu *s, struct cds_lfs_no | |
| ); | | de_rcu *node); | |
| | | | |
| /* | | /* | |
| * The caller must wait for a grace period to pass before freeing the retur
ned | | * The caller must wait for a grace period to pass before freeing the retur
ned | |
|
| * node or modifying the rcu_lfs_node structure. | | * node or modifying the cds_lfs_node_rcu structure. | |
| * Returns NULL if stack is empty. | | * Returns NULL if stack is empty. | |
| */ | | */ | |
|
| extern struct rcu_lfs_node *rcu_lfs_pop(struct rcu_lfs_stack *s); | | extern struct cds_lfs_node_rcu *cds_lfs_pop_rcu(struct cds_lfs_stack_rcu *s
); | |
| | | | |
| #endif /* !_LGPL_SOURCE */ | | #endif /* !_LGPL_SOURCE */ | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_RCULFSTACK_H */ | | #endif /* _URCU_RCULFSTACK_H */ | |
| | | | |
End of changes. 6 change blocks. |
| 14 lines changed or deleted | | 14 lines changed or added | |
|
| rculist.h | | rculist.h | |
| | | | |
| skipping to change at line 33 | | skipping to change at line 33 | |
| | | | |
| #ifndef _URCU_RCULIST_H | | #ifndef _URCU_RCULIST_H | |
| #define _URCU_RCULIST_H | | #define _URCU_RCULIST_H | |
| | | | |
| #include <urcu/list.h> | | #include <urcu/list.h> | |
| #include <urcu/arch.h> | | #include <urcu/arch.h> | |
| #include <urcu-pointer.h> | | #include <urcu-pointer.h> | |
| | | | |
| /* Add new element at the head of the list. | | /* Add new element at the head of the list. | |
| */ | | */ | |
|
| static inline void list_add_rcu(list_t *newp, list_t *head) | | static inline void cds_list_add_rcu(list_t *newp, list_t *head) | |
| { | | { | |
| newp->next = head->next; | | newp->next = head->next; | |
| newp->prev = head; | | newp->prev = head; | |
|
| smp_wmb(); | | cmm_smp_wmb(); | |
| head->next->prev = newp; | | head->next->prev = newp; | |
| head->next = newp; | | head->next = newp; | |
| } | | } | |
| | | | |
| /* replace an old entry atomically. | | /* replace an old entry atomically. | |
| */ | | */ | |
|
| static inline void list_replace_rcu(list_t *old, list_t *_new) | | static inline void cds_list_replace_rcu(list_t *old, list_t *_new) | |
| { | | { | |
| _new->next = old->next; | | _new->next = old->next; | |
| _new->prev = old->prev; | | _new->prev = old->prev; | |
| rcu_assign_pointer(_new->prev->next, _new); | | rcu_assign_pointer(_new->prev->next, _new); | |
| _new->next->prev = _new; | | _new->next->prev = _new; | |
| } | | } | |
| | | | |
| /* Remove element from list. */ | | /* Remove element from list. */ | |
|
| static inline void list_del_rcu(list_t *elem) | | static inline void cds_list_del_rcu(list_t *elem) | |
| { | | { | |
| elem->next->prev = elem->prev; | | elem->next->prev = elem->prev; | |
| elem->prev->next = elem->next; | | elem->prev->next = elem->next; | |
| } | | } | |
| | | | |
| /* | | /* | |
| * Iteration through all elements of the list must be done while rcu_read_l
ock() | | * Iteration through all elements of the list must be done while rcu_read_l
ock() | |
| * is held. | | * is held. | |
| */ | | */ | |
| | | | |
| /* Iterate forward over the elements of the list. */ | | /* Iterate forward over the elements of the list. */ | |
|
| #define list_for_each_rcu(pos, head) \ | | #define cds_list_for_each_rcu(pos, head) \ | |
| for (pos = rcu_dereference((head)->next); pos != (head); \ | | for (pos = rcu_dereference((head)->next); pos != (head); \ | |
| pos = rcu_dereference(pos->next)) | | pos = rcu_dereference(pos->next)) | |
| | | | |
| /* Iterate through elements of the list. | | /* Iterate through elements of the list. | |
| */ | | */ | |
|
| #define list_for_each_entry_rcu(pos, head, member) | | #define cds_list_for_each_entry_rcu(pos, head, member) | |
| \ | | \ | |
| for (pos = list_entry(rcu_dereference((head)->next), typeof(*pos), m | | for (pos = cds_list_entry(rcu_dereference((head)->next), typeof(*pos | |
| ember); \ | | ), member); \ | |
| &pos->member != (head); \ | | &pos->member != (head); \ | |
|
| pos = list_entry(rcu_dereference(pos->member.next), typeof(*pos
), member)) | | pos = cds_list_entry(rcu_dereference(pos->member.next), typeof(
*pos), member)) | |
| | | | |
| #endif /* _URCU_RCULIST_H */ | | #endif /* _URCU_RCULIST_H */ | |
| | | | |
End of changes. 7 change blocks. |
| 10 lines changed or deleted | | 10 lines changed or added | |
|
| system.h | | system.h | |
| | | | |
| skipping to change at line 25 | | skipping to change at line 25 | |
| * for any purpose, provided the above notices are retained on all copies. | | * for any purpose, provided the above notices are retained on all copies. | |
| * Permission to modify the code and to distribute modified code is granted
, | | * Permission to modify the code and to distribute modified code is granted
, | |
| * provided the above notices are retained, and a notice that the code was | | * provided the above notices are retained, and a notice that the code was | |
| * modified is included with the above copyright notice. | | * modified is included with the above copyright notice. | |
| */ | | */ | |
| | | | |
| #include <urcu/compiler.h> | | #include <urcu/compiler.h> | |
| #include <urcu/arch.h> | | #include <urcu/arch.h> | |
| | | | |
| /* | | /* | |
|
| * Identify a shared load. A smp_rmc() or smp_mc() should come before the l
oad. | | * Identify a shared load. A cmm_smp_rmc() or cmm_smp_mc() should come befo
re the load. | |
| */ | | */ | |
|
| #define _LOAD_SHARED(p) ACCESS_ONCE(p) | | #define _CAA_LOAD_SHARED(p) CAA_ACCESS_ONCE(p) | |
| | | | |
| /* | | /* | |
| * Load a data from shared memory, doing a cache flush if required. | | * Load a data from shared memory, doing a cache flush if required. | |
| */ | | */ | |
|
| #define LOAD_SHARED(p) \ | | #define CAA_LOAD_SHARED(p) \ | |
| ({ \ | | ({ \ | |
|
| smp_rmc(); \ | | cmm_smp_rmc(); \ | |
| _LOAD_SHARED(p); \ | | _CAA_LOAD_SHARED(p); \ | |
| }) | | }) | |
| | | | |
| /* | | /* | |
|
| * Identify a shared store. A smp_wmc() or smp_mc() should follow the store
. | | * Identify a shared store. A cmm_smp_wmc() or cmm_smp_mc() should follow t
he store. | |
| */ | | */ | |
|
| #define _STORE_SHARED(x, v) ({ ACCESS_ONCE(x) = (v); }) | | #define _CAA_STORE_SHARED(x, v) ({ CAA_ACCESS_ONCE(x) = (v); }) | |
| | | | |
| /* | | /* | |
| * Store v into x, where x is located in shared memory. Performs the requir
ed | | * Store v into x, where x is located in shared memory. Performs the requir
ed | |
| * cache flush after writing. Returns v. | | * cache flush after writing. Returns v. | |
| */ | | */ | |
|
| #define STORE_SHARED(x, v) \ | | #define CAA_STORE_SHARED(x, v) \ | |
| ({ \ | | ({ \ | |
|
| typeof(x) _v = _STORE_SHARED(x, v); \ | | typeof(x) _v = _CAA_STORE_SHARED(x, v); \ | |
| smp_wmc(); \ | | cmm_smp_wmc(); \ | |
| _v; \ | | _v; \ | |
| }) | | }) | |
| | | | |
| #endif /* _URCU_SYSTEM_H */ | | #endif /* _URCU_SYSTEM_H */ | |
| | | | |
End of changes. 8 change blocks. |
| 10 lines changed or deleted | | 10 lines changed or added | |
|
| urcu-bp-static.h | | urcu-bp-static.h | |
| | | | |
| skipping to change at line 143 | | skipping to change at line 143 | |
| * Global quiescent period counter with low-order bits unused. | | * Global quiescent period counter with low-order bits unused. | |
| * Using a int rather than a char to eliminate false register dependencies | | * Using a int rather than a char to eliminate false register dependencies | |
| * causing stalls on some architectures. | | * causing stalls on some architectures. | |
| */ | | */ | |
| extern long rcu_gp_ctr; | | extern long rcu_gp_ctr; | |
| | | | |
| struct rcu_reader { | | struct rcu_reader { | |
| /* Data used by both reader and synchronize_rcu() */ | | /* Data used by both reader and synchronize_rcu() */ | |
| long ctr; | | long ctr; | |
| /* Data used for registry */ | | /* Data used for registry */ | |
|
| struct list_head node __attribute__((aligned(CACHE_LINE_SIZE))); | | struct cds_list_head node __attribute__((aligned(CAA_CACHE_LINE_SIZE
))); | |
| pthread_t tid; | | pthread_t tid; | |
| int alloc; /* registry entry allocated */ | | int alloc; /* registry entry allocated */ | |
| }; | | }; | |
| | | | |
| /* | | /* | |
| * Bulletproof version keeps a pointer to a registry not part of the TLS. | | * Bulletproof version keeps a pointer to a registry not part of the TLS. | |
| * Adds a pointer dereference on the read-side, but won't require to unregi
ster | | * Adds a pointer dereference on the read-side, but won't require to unregi
ster | |
| * the reader thread. | | * the reader thread. | |
| */ | | */ | |
| extern struct rcu_reader __thread *rcu_reader; | | extern struct rcu_reader __thread *rcu_reader; | |
| | | | |
| skipping to change at line 165 | | skipping to change at line 165 | |
| static inline int rcu_old_gp_ongoing(long *value) | | static inline int rcu_old_gp_ongoing(long *value) | |
| { | | { | |
| long v; | | long v; | |
| | | | |
| if (value == NULL) | | if (value == NULL) | |
| return 0; | | return 0; | |
| /* | | /* | |
| * Make sure both tests below are done on the same version of *value | | * Make sure both tests below are done on the same version of *value | |
| * to insure consistency. | | * to insure consistency. | |
| */ | | */ | |
|
| v = LOAD_SHARED(*value); | | v = CAA_LOAD_SHARED(*value); | |
| return (v & RCU_GP_CTR_NEST_MASK) && | | return (v & RCU_GP_CTR_NEST_MASK) && | |
| ((v ^ rcu_gp_ctr) & RCU_GP_CTR_PHASE); | | ((v ^ rcu_gp_ctr) & RCU_GP_CTR_PHASE); | |
| } | | } | |
| | | | |
| static inline void _rcu_read_lock(void) | | static inline void _rcu_read_lock(void) | |
| { | | { | |
| long tmp; | | long tmp; | |
| | | | |
| /* Check if registered */ | | /* Check if registered */ | |
| if (unlikely(!rcu_reader)) | | if (unlikely(!rcu_reader)) | |
| rcu_bp_register(); | | rcu_bp_register(); | |
| | | | |
|
| | | cmm_barrier(); /* Ensure the compiler does not reorder us with mute
x */ | |
| tmp = rcu_reader->ctr; | | tmp = rcu_reader->ctr; | |
| /* | | /* | |
| * rcu_gp_ctr is | | * rcu_gp_ctr is | |
| * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) | | * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) | |
| */ | | */ | |
| if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { | | if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { | |
|
| _STORE_SHARED(rcu_reader->ctr, _LOAD_SHARED(rcu_gp_ctr)); | | _CAA_STORE_SHARED(rcu_reader->ctr, _CAA_LOAD_SHARED(rcu_gp_c
tr)); | |
| /* | | /* | |
| * Set active readers count for outermost nesting level befo
re | | * Set active readers count for outermost nesting level befo
re | |
| * accessing the pointer. | | * accessing the pointer. | |
| */ | | */ | |
|
| smp_mb(); | | cmm_smp_mb(); | |
| } else { | | } else { | |
|
| _STORE_SHARED(rcu_reader->ctr, tmp + RCU_GP_COUNT); | | _CAA_STORE_SHARED(rcu_reader->ctr, tmp + RCU_GP_COUNT); | |
| } | | } | |
| } | | } | |
| | | | |
| static inline void _rcu_read_unlock(void) | | static inline void _rcu_read_unlock(void) | |
| { | | { | |
| /* | | /* | |
| * Finish using rcu before decrementing the pointer. | | * Finish using rcu before decrementing the pointer. | |
| */ | | */ | |
|
| smp_mb(); | | cmm_smp_mb(); | |
| _STORE_SHARED(rcu_reader->ctr, rcu_reader->ctr - RCU_GP_COUNT); | | _CAA_STORE_SHARED(rcu_reader->ctr, rcu_reader->ctr - RCU_GP_COUNT); | |
| | | cmm_barrier(); /* Ensure the compiler does not reorder us with mute | |
| | | x */ | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_BP_STATIC_H */ | | #endif /* _URCU_BP_STATIC_H */ | |
| | | | |
End of changes. 7 change blocks. |
| 7 lines changed or deleted | | 10 lines changed or added | |
|
| urcu-pointer-static.h | | urcu-pointer-static.h | |
| | | | |
| skipping to change at line 52 | | skipping to change at line 52 | |
| * _rcu_dereference - reads (copy) a RCU-protected pointer to a local varia
ble | | * _rcu_dereference - reads (copy) a RCU-protected pointer to a local varia
ble | |
| * into a RCU read-side critical section. The pointer can later be safely | | * into a RCU read-side critical section. The pointer can later be safely | |
| * dereferenced within the critical section. | | * dereferenced within the critical section. | |
| * | | * | |
| * This ensures that the pointer copy is invariant thorough the whole criti
cal | | * This ensures that the pointer copy is invariant thorough the whole criti
cal | |
| * section. | | * section. | |
| * | | * | |
| * Inserts memory barriers on architectures that require them (currently on
ly | | * Inserts memory barriers on architectures that require them (currently on
ly | |
| * Alpha) and documents which pointers are protected by RCU. | | * Alpha) and documents which pointers are protected by RCU. | |
| * | | * | |
|
| * The compiler memory barrier in LOAD_SHARED() ensures that value-speculat
ive | | * The compiler memory barrier in CAA_LOAD_SHARED() ensures that value-spec
ulative | |
| * optimizations (e.g. VSS: Value Speculation Scheduling) does not perform
the | | * optimizations (e.g. VSS: Value Speculation Scheduling) does not perform
the | |
| * data read before the pointer read by speculating the value of the pointe
r. | | * data read before the pointer read by speculating the value of the pointe
r. | |
| * Correct ordering is ensured because the pointer is read as a volatile ac
cess. | | * Correct ordering is ensured because the pointer is read as a volatile ac
cess. | |
| * This acts as a global side-effect operation, which forbids reordering of | | * This acts as a global side-effect operation, which forbids reordering of | |
| * dependent memory operations. Note that such concern about dependency-bre
aking | | * dependent memory operations. Note that such concern about dependency-bre
aking | |
| * optimizations will eventually be taken care of by the "memory_order_cons
ume" | | * optimizations will eventually be taken care of by the "memory_order_cons
ume" | |
| * addition to forthcoming C++ standard. | | * addition to forthcoming C++ standard. | |
| * | | * | |
| * Should match rcu_assign_pointer() or rcu_xchg_pointer(). | | * Should match rcu_assign_pointer() or rcu_xchg_pointer(). | |
| */ | | */ | |
| | | | |
| #define _rcu_dereference(p) ({ \ | | #define _rcu_dereference(p) ({ \ | |
|
| typeof(p) _________p1 = LOAD_SHARED(p); \ | | typeof(p) _________p1 = CAA_LOAD_SHARED(p); | |
| smp_read_barrier_depends(); \ | | \ | |
| | | cmm_smp_read_barrier_depends(); \ | |
| (_________p1); \ | | (_________p1); \ | |
| }) | | }) | |
| | | | |
| /** | | /** | |
| * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the poin
ter | | * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the poin
ter | |
| * is as expected by "old". If succeeds, returns the previous pointer to th
e | | * is as expected by "old". If succeeds, returns the previous pointer to th
e | |
| * data structure, which can be safely freed after waiting for a quiescent
state | | * data structure, which can be safely freed after waiting for a quiescent
state | |
| * using synchronize_rcu(). If fails (unexpected value), returns old (which | | * using synchronize_rcu(). If fails (unexpected value), returns old (which | |
| * should not be freed !). | | * should not be freed !). | |
| */ | | */ | |
| | | | |
| #define _rcu_cmpxchg_pointer(p, old, _new) \ | | #define _rcu_cmpxchg_pointer(p, old, _new) \ | |
| ({ \ | | ({ \ | |
| typeof(*p) _________pold = (old); \ | | typeof(*p) _________pold = (old); \ | |
| typeof(*p) _________pnew = (_new); \ | | typeof(*p) _________pnew = (_new); \ | |
| if (!__builtin_constant_p(_new) || \ | | if (!__builtin_constant_p(_new) || \ | |
| ((_new) != NULL)) \ | | ((_new) != NULL)) \ | |
|
| wmb(); \ | | cmm_wmb();
\ | |
| uatomic_cmpxchg(p, _________pold, _________pnew); \ | | uatomic_cmpxchg(p, _________pold, _________pnew); \ | |
| }) | | }) | |
| | | | |
| /** | | /** | |
| * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous | | * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous | |
| * pointer to the data structure, which can be safely freed after waiting f
or a | | * pointer to the data structure, which can be safely freed after waiting f
or a | |
| * quiescent state using synchronize_rcu(). | | * quiescent state using synchronize_rcu(). | |
| */ | | */ | |
| | | | |
| #define _rcu_xchg_pointer(p, v) \ | | #define _rcu_xchg_pointer(p, v) \ | |
| ({ \ | | ({ \ | |
| typeof(*p) _________pv = (v); \ | | typeof(*p) _________pv = (v); \ | |
| if (!__builtin_constant_p(v) || \ | | if (!__builtin_constant_p(v) || \ | |
| ((v) != NULL)) \ | | ((v) != NULL)) \ | |
|
| wmb(); \ | | cmm_wmb(); \ | |
| uatomic_xchg(p, _________pv); \ | | uatomic_xchg(p, _________pv); \ | |
| }) | | }) | |
| | | | |
| #define _rcu_set_pointer(p, v) \ | | #define _rcu_set_pointer(p, v) \ | |
| ({ \ | | ({ \ | |
| typeof(*p) _________pv = (v); \ | | typeof(*p) _________pv = (v); \ | |
| if (!__builtin_constant_p(v) || \ | | if (!__builtin_constant_p(v) || \ | |
| ((v) != NULL)) \ | | ((v) != NULL)) \ | |
|
| wmb(); \ | | cmm_wmb(); \ | |
| uatomic_set(p, _________pv); \ | | uatomic_set(p, _________pv); \ | |
| }) | | }) | |
| | | | |
| /** | | /** | |
| * _rcu_assign_pointer - assign (publicize) a pointer to a new data structu
re | | * _rcu_assign_pointer - assign (publicize) a pointer to a new data structu
re | |
| * meant to be read by RCU read-side critical sections. Returns the assigne
d | | * meant to be read by RCU read-side critical sections. Returns the assigne
d | |
| * value. | | * value. | |
| * | | * | |
| * Documents which pointers will be dereferenced by RCU read-side critical | | * Documents which pointers will be dereferenced by RCU read-side critical | |
| * sections and adds the required memory barriers on architectures requirin
g | | * sections and adds the required memory barriers on architectures requirin
g | |
| | | | |
End of changes. 5 change blocks. |
| 6 lines changed or deleted | | 7 lines changed or added | |
|
| urcu-qsbr-static.h | | urcu-qsbr-static.h | |
| | | | |
| skipping to change at line 138 | | skipping to change at line 138 | |
| * Global quiescent period counter with low-order bits unused. | | * Global quiescent period counter with low-order bits unused. | |
| * Using a int rather than a char to eliminate false register dependencies | | * Using a int rather than a char to eliminate false register dependencies | |
| * causing stalls on some architectures. | | * causing stalls on some architectures. | |
| */ | | */ | |
| extern unsigned long rcu_gp_ctr; | | extern unsigned long rcu_gp_ctr; | |
| | | | |
| struct rcu_reader { | | struct rcu_reader { | |
| /* Data used by both reader and synchronize_rcu() */ | | /* Data used by both reader and synchronize_rcu() */ | |
| unsigned long ctr; | | unsigned long ctr; | |
| /* Data used for registry */ | | /* Data used for registry */ | |
|
| struct list_head node __attribute__((aligned(CACHE_LINE_SIZE))); | | struct cds_list_head node __attribute__((aligned(CAA_CACHE_LINE_SIZE
))); | |
| pthread_t tid; | | pthread_t tid; | |
| }; | | }; | |
| | | | |
| extern struct rcu_reader __thread rcu_reader; | | extern struct rcu_reader __thread rcu_reader; | |
| | | | |
| extern int gp_futex; | | extern int gp_futex; | |
| | | | |
| /* | | /* | |
| * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. | | * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. | |
| */ | | */ | |
| | | | |
| skipping to change at line 162 | | skipping to change at line 162 | |
| uatomic_set(&gp_futex, 0); | | uatomic_set(&gp_futex, 0); | |
| futex_noasync(&gp_futex, FUTEX_WAKE, 1, | | futex_noasync(&gp_futex, FUTEX_WAKE, 1, | |
| NULL, NULL, 0); | | NULL, NULL, 0); | |
| } | | } | |
| } | | } | |
| | | | |
| static inline int rcu_gp_ongoing(unsigned long *ctr) | | static inline int rcu_gp_ongoing(unsigned long *ctr) | |
| { | | { | |
| unsigned long v; | | unsigned long v; | |
| | | | |
|
| v = LOAD_SHARED(*ctr); | | v = CAA_LOAD_SHARED(*ctr); | |
| return v && (v != rcu_gp_ctr); | | return v && (v != rcu_gp_ctr); | |
| } | | } | |
| | | | |
| static inline void _rcu_read_lock(void) | | static inline void _rcu_read_lock(void) | |
| { | | { | |
| rcu_assert(rcu_reader.ctr); | | rcu_assert(rcu_reader.ctr); | |
| } | | } | |
| | | | |
| static inline void _rcu_read_unlock(void) | | static inline void _rcu_read_unlock(void) | |
| { | | { | |
| } | | } | |
| | | | |
| static inline void _rcu_quiescent_state(void) | | static inline void _rcu_quiescent_state(void) | |
| { | | { | |
|
| smp_mb(); | | cmm_smp_mb(); | |
| _STORE_SHARED(rcu_reader.ctr, _LOAD_SHARED(rcu_gp_ctr)); | | _CAA_STORE_SHARED(rcu_reader.ctr, _CAA_LOAD_SHARED(rcu_gp_ctr)); | |
| smp_mb(); /* write rcu_reader.ctr before read futex */ | | cmm_smp_mb(); /* write rcu_reader.ctr before read futex */ | |
| wake_up_gp(); | | wake_up_gp(); | |
|
| smp_mb(); | | cmm_smp_mb(); | |
| } | | } | |
| | | | |
| static inline void _rcu_thread_offline(void) | | static inline void _rcu_thread_offline(void) | |
| { | | { | |
|
| smp_mb(); | | cmm_smp_mb(); | |
| STORE_SHARED(rcu_reader.ctr, 0); | | CAA_STORE_SHARED(rcu_reader.ctr, 0); | |
| smp_mb(); /* write rcu_reader.ctr before read futex */ | | cmm_smp_mb(); /* write rcu_reader.ctr before read futex */ | |
| wake_up_gp(); | | wake_up_gp(); | |
|
| | | cmm_barrier(); /* Ensure the compiler does not reorder us with mute
x */ | |
| } | | } | |
| | | | |
| static inline void _rcu_thread_online(void) | | static inline void _rcu_thread_online(void) | |
| { | | { | |
|
| _STORE_SHARED(rcu_reader.ctr, LOAD_SHARED(rcu_gp_ctr)); | | cmm_barrier(); /* Ensure the compiler does not reorder us with mute | |
| smp_mb(); | | x */ | |
| | | _CAA_STORE_SHARED(rcu_reader.ctr, CAA_LOAD_SHARED(rcu_gp_ctr)); | |
| | | cmm_smp_mb(); | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_QSBR_STATIC_H */ | | #endif /* _URCU_QSBR_STATIC_H */ | |
| | | | |
End of changes. 7 change blocks. |
| 11 lines changed or deleted | | 14 lines changed or added | |
|
| urcu-static.h | | urcu-static.h | |
| | | | |
| skipping to change at line 184 | | skipping to change at line 184 | |
| | | | |
| #define MB_GROUP_ALL 0 | | #define MB_GROUP_ALL 0 | |
| #define RCU_MB_GROUP MB_GROUP_ALL | | #define RCU_MB_GROUP MB_GROUP_ALL | |
| | | | |
| #ifdef RCU_MEMBARRIER | | #ifdef RCU_MEMBARRIER | |
| extern int has_sys_membarrier; | | extern int has_sys_membarrier; | |
| | | | |
| static inline void smp_mb_slave(int group) | | static inline void smp_mb_slave(int group) | |
| { | | { | |
| if (likely(has_sys_membarrier)) | | if (likely(has_sys_membarrier)) | |
|
| barrier(); | | cmm_barrier(); | |
| else | | else | |
|
| smp_mb(); | | cmm_smp_mb(); | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #ifdef RCU_MB | | #ifdef RCU_MB | |
| static inline void smp_mb_slave(int group) | | static inline void smp_mb_slave(int group) | |
| { | | { | |
|
| smp_mb(); | | cmm_smp_mb(); | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #ifdef RCU_SIGNAL | | #ifdef RCU_SIGNAL | |
| static inline void smp_mb_slave(int group) | | static inline void smp_mb_slave(int group) | |
| { | | { | |
|
| barrier(); | | cmm_barrier(); | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| /* | | /* | |
| * The trick here is that RCU_GP_CTR_PHASE must be a multiple of 8 so we ca
n use | | * The trick here is that RCU_GP_CTR_PHASE must be a multiple of 8 so we ca
n use | |
| * a full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. | | * a full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. | |
| */ | | */ | |
| #define RCU_GP_COUNT (1UL << 0) | | #define RCU_GP_COUNT (1UL << 0) | |
| /* Use the amount of bits equal to half of the architecture long size */ | | /* Use the amount of bits equal to half of the architecture long size */ | |
| #define RCU_GP_CTR_PHASE (1UL << (sizeof(unsigned long) << 2)) | | #define RCU_GP_CTR_PHASE (1UL << (sizeof(unsigned long) << 2)) | |
| | | | |
| skipping to change at line 225 | | skipping to change at line 225 | |
| * Using a int rather than a char to eliminate false register dependencies | | * Using a int rather than a char to eliminate false register dependencies | |
| * causing stalls on some architectures. | | * causing stalls on some architectures. | |
| */ | | */ | |
| extern unsigned long rcu_gp_ctr; | | extern unsigned long rcu_gp_ctr; | |
| | | | |
| struct rcu_reader { | | struct rcu_reader { | |
| /* Data used by both reader and synchronize_rcu() */ | | /* Data used by both reader and synchronize_rcu() */ | |
| unsigned long ctr; | | unsigned long ctr; | |
| char need_mb; | | char need_mb; | |
| /* Data used for registry */ | | /* Data used for registry */ | |
|
| struct list_head node __attribute__((aligned(CACHE_LINE_SIZE))); | | struct cds_list_head node __attribute__((aligned(CAA_CACHE_LINE_SIZE
))); | |
| pthread_t tid; | | pthread_t tid; | |
| }; | | }; | |
| | | | |
| extern struct rcu_reader __thread rcu_reader; | | extern struct rcu_reader __thread rcu_reader; | |
| | | | |
| extern int gp_futex; | | extern int gp_futex; | |
| | | | |
| /* | | /* | |
| * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. | | * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. | |
| */ | | */ | |
| | | | |
| skipping to change at line 253 | | skipping to change at line 253 | |
| } | | } | |
| | | | |
| static inline int rcu_gp_ongoing(unsigned long *ctr) | | static inline int rcu_gp_ongoing(unsigned long *ctr) | |
| { | | { | |
| unsigned long v; | | unsigned long v; | |
| | | | |
| /* | | /* | |
| * Make sure both tests below are done on the same version of *value | | * Make sure both tests below are done on the same version of *value | |
| * to insure consistency. | | * to insure consistency. | |
| */ | | */ | |
|
| v = LOAD_SHARED(*ctr); | | v = CAA_LOAD_SHARED(*ctr); | |
| return (v & RCU_GP_CTR_NEST_MASK) && | | return (v & RCU_GP_CTR_NEST_MASK) && | |
| ((v ^ rcu_gp_ctr) & RCU_GP_CTR_PHASE); | | ((v ^ rcu_gp_ctr) & RCU_GP_CTR_PHASE); | |
| } | | } | |
| | | | |
| static inline void _rcu_read_lock(void) | | static inline void _rcu_read_lock(void) | |
| { | | { | |
| unsigned long tmp; | | unsigned long tmp; | |
| | | | |
|
| | | cmm_barrier(); /* Ensure the compiler does not reorder us with mute
x */ | |
| tmp = rcu_reader.ctr; | | tmp = rcu_reader.ctr; | |
| /* | | /* | |
| * rcu_gp_ctr is | | * rcu_gp_ctr is | |
| * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) | | * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) | |
| */ | | */ | |
| if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { | | if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { | |
|
| _STORE_SHARED(rcu_reader.ctr, _LOAD_SHARED(rcu_gp_ctr)); | | _CAA_STORE_SHARED(rcu_reader.ctr, _CAA_LOAD_SHARED(rcu_gp_ct
r)); | |
| /* | | /* | |
| * Set active readers count for outermost nesting level befo
re | | * Set active readers count for outermost nesting level befo
re | |
| * accessing the pointer. See smp_mb_master(). | | * accessing the pointer. See smp_mb_master(). | |
| */ | | */ | |
| smp_mb_slave(RCU_MB_GROUP); | | smp_mb_slave(RCU_MB_GROUP); | |
| } else { | | } else { | |
|
| _STORE_SHARED(rcu_reader.ctr, tmp + RCU_GP_COUNT); | | _CAA_STORE_SHARED(rcu_reader.ctr, tmp + RCU_GP_COUNT); | |
| } | | } | |
| } | | } | |
| | | | |
| static inline void _rcu_read_unlock(void) | | static inline void _rcu_read_unlock(void) | |
| { | | { | |
| unsigned long tmp; | | unsigned long tmp; | |
| | | | |
| tmp = rcu_reader.ctr; | | tmp = rcu_reader.ctr; | |
| /* | | /* | |
| * Finish using rcu before decrementing the pointer. | | * Finish using rcu before decrementing the pointer. | |
| * See smp_mb_master(). | | * See smp_mb_master(). | |
| */ | | */ | |
| if (likely((tmp & RCU_GP_CTR_NEST_MASK) == RCU_GP_COUNT)) { | | if (likely((tmp & RCU_GP_CTR_NEST_MASK) == RCU_GP_COUNT)) { | |
| smp_mb_slave(RCU_MB_GROUP); | | smp_mb_slave(RCU_MB_GROUP); | |
|
| _STORE_SHARED(rcu_reader.ctr, rcu_reader.ctr - RCU_GP_COUNT)
; | | _CAA_STORE_SHARED(rcu_reader.ctr, rcu_reader.ctr - RCU_GP_CO
UNT); | |
| /* write rcu_reader.ctr before read futex */ | | /* write rcu_reader.ctr before read futex */ | |
| smp_mb_slave(RCU_MB_GROUP); | | smp_mb_slave(RCU_MB_GROUP); | |
| wake_up_gp(); | | wake_up_gp(); | |
| } else { | | } else { | |
|
| _STORE_SHARED(rcu_reader.ctr, rcu_reader.ctr - RCU_GP_COUNT)
; | | _CAA_STORE_SHARED(rcu_reader.ctr, rcu_reader.ctr - RCU_GP_CO
UNT); | |
| } | | } | |
|
| | | cmm_barrier(); /* Ensure the compiler does not reorder us with mute
x */ | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_STATIC_H */ | | #endif /* _URCU_STATIC_H */ | |
| | | | |
End of changes. 12 change blocks. |
| 10 lines changed or deleted | | 12 lines changed or added | |
|
| wfqueue-static.h | | wfqueue-static.h | |
| | | | |
| skipping to change at line 50 | | skipping to change at line 50 | |
| * This implementation adds a dummy head node when the queue is empty to en
sure | | * This implementation adds a dummy head node when the queue is empty to en
sure | |
| * we can always update the queue locklessly. | | * we can always update the queue locklessly. | |
| * | | * | |
| * Inspired from half-wait-free/half-blocking queue implementation done by | | * Inspired from half-wait-free/half-blocking queue implementation done by | |
| * Paul E. McKenney. | | * Paul E. McKenney. | |
| */ | | */ | |
| | | | |
| #define WFQ_ADAPT_ATTEMPTS 10 /* Retry if being set */ | | #define WFQ_ADAPT_ATTEMPTS 10 /* Retry if being set */ | |
| #define WFQ_WAIT 10 /* Wait 10 ms if being set *
/ | | #define WFQ_WAIT 10 /* Wait 10 ms if being set *
/ | |
| | | | |
|
| void _wfq_node_init(struct wfq_node *node) | | void _cds_wfq_node_init(struct cds_wfq_node *node) | |
| { | | { | |
| node->next = NULL; | | node->next = NULL; | |
| } | | } | |
| | | | |
|
| void _wfq_init(struct wfq_queue *q) | | void _cds_wfq_init(struct cds_wfq_queue *q) | |
| { | | { | |
| int ret; | | int ret; | |
| | | | |
|
| _wfq_node_init(&q->dummy); | | _cds_wfq_node_init(&q->dummy); | |
| /* Set queue head and tail */ | | /* Set queue head and tail */ | |
| q->head = &q->dummy; | | q->head = &q->dummy; | |
| q->tail = &q->dummy.next; | | q->tail = &q->dummy.next; | |
| ret = pthread_mutex_init(&q->lock, NULL); | | ret = pthread_mutex_init(&q->lock, NULL); | |
| assert(!ret); | | assert(!ret); | |
| } | | } | |
| | | | |
|
| void _wfq_enqueue(struct wfq_queue *q, struct wfq_node *node) | | void _cds_wfq_enqueue(struct cds_wfq_queue *q, struct cds_wfq_node *node) | |
| { | | { | |
|
| struct wfq_node **old_tail; | | struct cds_wfq_node **old_tail; | |
| | | | |
| /* | | /* | |
| * uatomic_xchg() implicit memory barrier orders earlier stores to d
ata | | * uatomic_xchg() implicit memory barrier orders earlier stores to d
ata | |
| * structure containing node and setting node->next to NULL before | | * structure containing node and setting node->next to NULL before | |
| * publication. | | * publication. | |
| */ | | */ | |
| old_tail = uatomic_xchg(&q->tail, node); | | old_tail = uatomic_xchg(&q->tail, node); | |
| /* | | /* | |
| * At this point, dequeuers see a NULL old_tail->next, which indicat
es | | * At this point, dequeuers see a NULL old_tail->next, which indicat
es | |
| * that the queue is being appended to. The following store will app
end | | * that the queue is being appended to. The following store will app
end | |
| * "node" to the queue from a dequeuer perspective. | | * "node" to the queue from a dequeuer perspective. | |
| */ | | */ | |
|
| STORE_SHARED(*old_tail, node); | | CAA_STORE_SHARED(*old_tail, node); | |
| } | | } | |
| | | | |
| /* | | /* | |
| * It is valid to reuse and free a dequeued node immediately. | | * It is valid to reuse and free a dequeued node immediately. | |
| * | | * | |
| * No need to go on a waitqueue here, as there is no possible state in whic
h the | | * No need to go on a waitqueue here, as there is no possible state in whic
h the | |
| * list could cause dequeue to busy-loop needlessly while waiting for anoth
er | | * list could cause dequeue to busy-loop needlessly while waiting for anoth
er | |
| * thread to be scheduled. The queue appears empty until tail->next is set
by | | * thread to be scheduled. The queue appears empty until tail->next is set
by | |
| * enqueue. | | * enqueue. | |
| */ | | */ | |
|
| struct wfq_node * | | struct cds_wfq_node * | |
| ___wfq_dequeue_blocking(struct wfq_queue *q) | | ___cds_wfq_dequeue_blocking(struct cds_wfq_queue *q) | |
| { | | { | |
|
| struct wfq_node *node, *next; | | struct cds_wfq_node *node, *next; | |
| int attempt = 0; | | int attempt = 0; | |
| | | | |
| /* | | /* | |
| * Queue is empty if it only contains the dummy node. | | * Queue is empty if it only contains the dummy node. | |
| */ | | */ | |
|
| if (q->head == &q->dummy && LOAD_SHARED(q->tail) == &q->dummy.next) | | if (q->head == &q->dummy && CAA_LOAD_SHARED(q->tail) == &q->dummy.ne
xt) | |
| return NULL; | | return NULL; | |
| node = q->head; | | node = q->head; | |
| | | | |
| /* | | /* | |
| * Adaptative busy-looping waiting for enqueuer to complete enqueue. | | * Adaptative busy-looping waiting for enqueuer to complete enqueue. | |
| */ | | */ | |
|
| while ((next = LOAD_SHARED(node->next)) == NULL) { | | while ((next = CAA_LOAD_SHARED(node->next)) == NULL) { | |
| if (++attempt >= WFQ_ADAPT_ATTEMPTS) { | | if (++attempt >= WFQ_ADAPT_ATTEMPTS) { | |
| poll(NULL, 0, WFQ_WAIT); /* Wait for 10ms */ | | poll(NULL, 0, WFQ_WAIT); /* Wait for 10ms */ | |
| attempt = 0; | | attempt = 0; | |
| } else | | } else | |
|
| cpu_relax(); | | caa_cpu_relax(); | |
| } | | } | |
| /* | | /* | |
| * Move queue head forward. | | * Move queue head forward. | |
| */ | | */ | |
| q->head = next; | | q->head = next; | |
| /* | | /* | |
| * Requeue dummy node if we just dequeued it. | | * Requeue dummy node if we just dequeued it. | |
| */ | | */ | |
| if (node == &q->dummy) { | | if (node == &q->dummy) { | |
|
| _wfq_node_init(node); | | _cds_wfq_node_init(node); | |
| _wfq_enqueue(q, node); | | _cds_wfq_enqueue(q, node); | |
| return ___wfq_dequeue_blocking(q); | | return ___cds_wfq_dequeue_blocking(q); | |
| } | | } | |
| return node; | | return node; | |
| } | | } | |
| | | | |
|
| struct wfq_node * | | struct cds_wfq_node * | |
| _wfq_dequeue_blocking(struct wfq_queue *q) | | _cds_wfq_dequeue_blocking(struct cds_wfq_queue *q) | |
| { | | { | |
|
| struct wfq_node *retnode; | | struct cds_wfq_node *retnode; | |
| int ret; | | int ret; | |
| | | | |
| ret = pthread_mutex_lock(&q->lock); | | ret = pthread_mutex_lock(&q->lock); | |
| assert(!ret); | | assert(!ret); | |
|
| retnode = ___wfq_dequeue_blocking(q); | | retnode = ___cds_wfq_dequeue_blocking(q); | |
| ret = pthread_mutex_unlock(&q->lock); | | ret = pthread_mutex_unlock(&q->lock); | |
| assert(!ret); | | assert(!ret); | |
| return retnode; | | return retnode; | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_WFQUEUE_STATIC_H */ | | #endif /* _URCU_WFQUEUE_STATIC_H */ | |
| | | | |
End of changes. 15 change blocks. |
| 19 lines changed or deleted | | 19 lines changed or added | |
|
| wfqueue.h | | wfqueue.h | |
| | | | |
| skipping to change at line 43 | | skipping to change at line 43 | |
| | | | |
| /* | | /* | |
| * Queue with wait-free enqueue/blocking dequeue. | | * Queue with wait-free enqueue/blocking dequeue. | |
| * This implementation adds a dummy head node when the queue is empty to en
sure | | * This implementation adds a dummy head node when the queue is empty to en
sure | |
| * we can always update the queue locklessly. | | * we can always update the queue locklessly. | |
| * | | * | |
| * Inspired from half-wait-free/half-blocking queue implementation done by | | * Inspired from half-wait-free/half-blocking queue implementation done by | |
| * Paul E. McKenney. | | * Paul E. McKenney. | |
| */ | | */ | |
| | | | |
|
| struct wfq_node { | | struct cds_wfq_node { | |
| struct wfq_node *next; | | struct cds_wfq_node *next; | |
| }; | | }; | |
| | | | |
|
| struct wfq_queue { | | struct cds_wfq_queue { | |
| struct wfq_node *head, **tail; | | struct cds_wfq_node *head, **tail; | |
| struct wfq_node dummy; /* Dummy node */ | | struct cds_wfq_node dummy; /* Dummy node */ | |
| pthread_mutex_t lock; | | pthread_mutex_t lock; | |
| }; | | }; | |
| | | | |
| #ifdef _LGPL_SOURCE | | #ifdef _LGPL_SOURCE | |
| | | | |
| #include <urcu/wfqueue-static.h> | | #include <urcu/wfqueue-static.h> | |
| | | | |
|
| #define wfq_node_init _wfq_node_init | | #define cds_wfq_node_init _cds_wfq_node_init | |
| #define wfq_init _wfq_init | | #define cds_wfq_init _cds_wfq_init | |
| #define wfq_enqueue _wfq_enqueue | | #define cds_wfq_enqueue _cds_wfq_enqueue | |
| #define __wfq_dequeue_blocking ___wfq_dequeue_blocking | | #define __cds_wfq_dequeue_blocking ___cds_wfq_dequeue_blocking | |
| #define wfq_dequeue_blocking _wfq_dequeue_blocking | | #define cds_wfq_dequeue_blocking _cds_wfq_dequeue_blocking | |
| | | | |
| #else /* !_LGPL_SOURCE */ | | #else /* !_LGPL_SOURCE */ | |
| | | | |
|
| extern void wfq_node_init(struct wfq_node *node); | | extern void cds_wfq_node_init(struct cds_wfq_node *node); | |
| extern void wfq_init(struct wfq_queue *q); | | extern void cds_wfq_init(struct cds_wfq_queue *q); | |
| extern void wfq_enqueue(struct wfq_queue *q, struct wfq_node *node); | | extern void cds_wfq_enqueue(struct cds_wfq_queue *q, struct cds_wfq_node *n | |
| /* __wfq_dequeue_blocking: caller ensures mutual exclusion between dequeues | | ode); | |
| */ | | /* __cds_wfq_dequeue_blocking: caller ensures mutual exclusion between dequ | |
| extern struct wfq_node *__wfq_dequeue_blocking(struct wfq_queue *q); | | eues */ | |
| extern struct wfq_node *wfq_dequeue_blocking(struct wfq_queue *q); | | extern struct cds_wfq_node *__cds_wfq_dequeue_blocking(struct cds_wfq_queue | |
| | | *q); | |
| | | extern struct cds_wfq_node *cds_wfq_dequeue_blocking(struct cds_wfq_queue * | |
| | | q); | |
| | | | |
| #endif /* !_LGPL_SOURCE */ | | #endif /* !_LGPL_SOURCE */ | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_WFQUEUE_H */ | | #endif /* _URCU_WFQUEUE_H */ | |
| | | | |
End of changes. 4 change blocks. |
| 17 lines changed or deleted | | 20 lines changed or added | |
|
| wfstack-static.h | | wfstack-static.h | |
| | | | |
| skipping to change at line 38 | | skipping to change at line 38 | |
| | | | |
| #include <pthread.h> | | #include <pthread.h> | |
| #include <assert.h> | | #include <assert.h> | |
| #include <urcu/compiler.h> | | #include <urcu/compiler.h> | |
| #include <urcu/uatomic_arch.h> | | #include <urcu/uatomic_arch.h> | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| #define WF_STACK_END ((void *)0x1UL) | | #define CDS_WF_STACK_END ((void *)0x1UL) | |
| #define WFS_ADAPT_ATTEMPTS 10 /* Retry if being set */ | | #define CDS_WFS_ADAPT_ATTEMPTS 10 /* Retry if being set */ | |
| #define WFS_WAIT 10 /* Wait 10 ms if being set * | | #define CDS_WFS_WAIT 10 /* Wait 10 ms if being set * | |
| / | | / | |
| | | | |
|
| void _wfs_node_init(struct wfs_node *node) | | void _cds_wfs_node_init(struct cds_wfs_node *node) | |
| { | | { | |
| node->next = NULL; | | node->next = NULL; | |
| } | | } | |
| | | | |
|
| void _wfs_init(struct wfs_stack *s) | | void _cds_wfs_init(struct cds_wfs_stack *s) | |
| { | | { | |
| int ret; | | int ret; | |
| | | | |
|
| s->head = WF_STACK_END; | | s->head = CDS_WF_STACK_END; | |
| ret = pthread_mutex_init(&s->lock, NULL); | | ret = pthread_mutex_init(&s->lock, NULL); | |
| assert(!ret); | | assert(!ret); | |
| } | | } | |
| | | | |
|
| void _wfs_push(struct wfs_stack *s, struct wfs_node *node) | | void _cds_wfs_push(struct cds_wfs_stack *s, struct cds_wfs_node *node) | |
| { | | { | |
|
| struct wfs_node *old_head; | | struct cds_wfs_node *old_head; | |
| | | | |
| assert(node->next == NULL); | | assert(node->next == NULL); | |
| /* | | /* | |
| * uatomic_xchg() implicit memory barrier orders earlier stores to n
ode | | * uatomic_xchg() implicit memory barrier orders earlier stores to n
ode | |
| * (setting it to NULL) before publication. | | * (setting it to NULL) before publication. | |
| */ | | */ | |
| old_head = uatomic_xchg(&s->head, node); | | old_head = uatomic_xchg(&s->head, node); | |
| /* | | /* | |
| * At this point, dequeuers see a NULL node->next, they should busy-
wait | | * At this point, dequeuers see a NULL node->next, they should busy-
wait | |
| * until node->next is set to old_head. | | * until node->next is set to old_head. | |
| */ | | */ | |
|
| STORE_SHARED(node->next, old_head); | | CAA_STORE_SHARED(node->next, old_head); | |
| } | | } | |
| | | | |
| /* | | /* | |
| * Returns NULL if stack is empty. | | * Returns NULL if stack is empty. | |
| */ | | */ | |
|
| struct wfs_node * | | struct cds_wfs_node * | |
| ___wfs_pop_blocking(struct wfs_stack *s) | | ___cds_wfs_pop_blocking(struct cds_wfs_stack *s) | |
| { | | { | |
|
| struct wfs_node *head, *next; | | struct cds_wfs_node *head, *next; | |
| int attempt = 0; | | int attempt = 0; | |
| | | | |
| retry: | | retry: | |
|
| head = LOAD_SHARED(s->head); | | head = CAA_LOAD_SHARED(s->head); | |
| if (head == WF_STACK_END) | | if (head == CDS_WF_STACK_END) | |
| return NULL; | | return NULL; | |
| /* | | /* | |
| * Adaptative busy-looping waiting for push to complete. | | * Adaptative busy-looping waiting for push to complete. | |
| */ | | */ | |
|
| while ((next = LOAD_SHARED(head->next)) == NULL) { | | while ((next = CAA_LOAD_SHARED(head->next)) == NULL) { | |
| if (++attempt >= WFS_ADAPT_ATTEMPTS) { | | if (++attempt >= CDS_WFS_ADAPT_ATTEMPTS) { | |
| poll(NULL, 0, WFS_WAIT); /* Wait for 10ms */ | | poll(NULL, 0, CDS_WFS_WAIT); /* Wait for 10ms */ | |
| attempt = 0; | | attempt = 0; | |
| } else | | } else | |
|
| cpu_relax(); | | caa_cpu_relax(); | |
| } | | } | |
| if (uatomic_cmpxchg(&s->head, head, next) == head) | | if (uatomic_cmpxchg(&s->head, head, next) == head) | |
| return head; | | return head; | |
| else | | else | |
| goto retry; /* Concurrent modification. Retry. *
/ | | goto retry; /* Concurrent modification. Retry. *
/ | |
| } | | } | |
| | | | |
|
| struct wfs_node * | | struct cds_wfs_node * | |
| _wfs_pop_blocking(struct wfs_stack *s) | | _cds_wfs_pop_blocking(struct cds_wfs_stack *s) | |
| { | | { | |
|
| struct wfs_node *retnode; | | struct cds_wfs_node *retnode; | |
| int ret; | | int ret; | |
| | | | |
| ret = pthread_mutex_lock(&s->lock); | | ret = pthread_mutex_lock(&s->lock); | |
| assert(!ret); | | assert(!ret); | |
|
| retnode = ___wfs_pop_blocking(s); | | retnode = ___cds_wfs_pop_blocking(s); | |
| ret = pthread_mutex_unlock(&s->lock); | | ret = pthread_mutex_unlock(&s->lock); | |
| assert(!ret); | | assert(!ret); | |
| return retnode; | | return retnode; | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_WFSTACK_STATIC_H */ | | #endif /* _URCU_WFSTACK_STATIC_H */ | |
| | | | |
End of changes. 15 change blocks. |
| 23 lines changed or deleted | | 23 lines changed or added | |
|
| wfstack.h | | wfstack.h | |
| | | | |
| skipping to change at line 34 | | skipping to change at line 34 | |
| */ | | */ | |
| | | | |
| #include <pthread.h> | | #include <pthread.h> | |
| #include <assert.h> | | #include <assert.h> | |
| #include <urcu/compiler.h> | | #include <urcu/compiler.h> | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| struct wfs_node { | | struct cds_wfs_node { | |
| struct wfs_node *next; | | struct cds_wfs_node *next; | |
| }; | | }; | |
| | | | |
|
| struct wfs_stack { | | struct cds_wfs_stack { | |
| struct wfs_node *head; | | struct cds_wfs_node *head; | |
| pthread_mutex_t lock; | | pthread_mutex_t lock; | |
| }; | | }; | |
| | | | |
| #ifdef _LGPL_SOURCE | | #ifdef _LGPL_SOURCE | |
| | | | |
| #include <urcu/wfstack-static.h> | | #include <urcu/wfstack-static.h> | |
| | | | |
|
| #define wfs_node_init _wfs_node_init | | #define cds_wfs_node_init _cds_wfs_node_init | |
| #define wfs_init _wfs_init | | #define cds_wfs_init _cds_wfs_init | |
| #define wfs_push _wfs_push | | #define cds_wfs_push _cds_wfs_push | |
| #define __wfs_pop_blocking ___wfs_pop_blocking | | #define __cds_wfs_pop_blocking ___cds_wfs_pop_blocking | |
| #define wfs_pop_blocking _wfs_pop_blocking | | #define cds_wfs_pop_blocking _cds_wfs_pop_blocking | |
| | | | |
| #else /* !_LGPL_SOURCE */ | | #else /* !_LGPL_SOURCE */ | |
| | | | |
|
| extern void wfs_node_init(struct wfs_node *node); | | extern void cds_wfs_node_init(struct cds_wfs_node *node); | |
| extern void wfs_init(struct wfs_stack *s); | | extern void cds_wfs_init(struct cds_wfs_stack *s); | |
| extern void wfs_push(struct wfs_stack *s, struct wfs_node *node); | | extern void cds_wfs_push(struct cds_wfs_stack *s, struct cds_wfs_node *node | |
| /* __wfs_pop_blocking: caller ensures mutual exclusion between pops */ | | ); | |
| extern struct wfs_node *__wfs_pop_blocking(struct wfs_stack *s); | | /* __cds_wfs_pop_blocking: caller ensures mutual exclusion between pops */ | |
| extern struct wfs_node *wfs_pop_blocking(struct wfs_stack *s); | | extern struct cds_wfs_node *__cds_wfs_pop_blocking(struct cds_wfs_stack *s) | |
| | | ; | |
| | | extern struct cds_wfs_node *cds_wfs_pop_blocking(struct cds_wfs_stack *s); | |
| | | | |
| #endif /* !_LGPL_SOURCE */ | | #endif /* !_LGPL_SOURCE */ | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_WFSTACK_H */ | | #endif /* _URCU_WFSTACK_H */ | |
| | | | |
End of changes. 4 change blocks. |
| 15 lines changed or deleted | | 17 lines changed or added | |
|