X-Git-Url: http://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=urcu-bp.c;h=22e17ccdd0a81eafe3b49917bb610f10a5e2ac3c;hp=4dc402865a026800ccef0bb35378be6241c81505;hb=d3ac5bb7c43cbe5412a4e3a13692ec7a90b9fbbb;hpb=731ccb963c80afd067e20acee2f9bd7cb4875ffb diff --git a/urcu-bp.c b/urcu-bp.c index 4dc4028..22e17cc 100644 --- a/urcu-bp.c +++ b/urcu-bp.c @@ -36,6 +36,7 @@ #include #include +#include "urcu/arch.h" #include "urcu/wfcqueue.h" #include "urcu/map/urcu-bp.h" #include "urcu/static/urcu-bp.h" @@ -94,11 +95,25 @@ void *mremap_wrapper(void *old_address, size_t old_size, static int rcu_bp_refcount; +/* If the headers do not support membarrier system call, fall back smp_mb. */ +#ifdef __NR_membarrier +# define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__) +#else +# define membarrier(...) -ENOSYS +#endif + +enum membarrier_cmd { + MEMBARRIER_CMD_QUERY = 0, + MEMBARRIER_CMD_SHARED = (1 << 0), +}; + static void __attribute__((constructor)) rcu_bp_init(void); static void __attribute__((destructor)) rcu_bp_exit(void); +int urcu_bp_has_sys_membarrier; + /* * rcu_gp_lock ensures mutual exclusion between threads calling * synchronize_rcu(). @@ -174,6 +189,14 @@ static void mutex_unlock(pthread_mutex_t *mutex) urcu_die(ret); } +static void smp_mb_master(void) +{ + if (caa_likely(urcu_bp_has_sys_membarrier)) + (void) membarrier(MEMBARRIER_CMD_SHARED, 0); + else + cmm_smp_mb(); +} + /* * Always called with rcu_registry lock held. Releases this lock between * iterations and grabs it again. Holds the lock when it returns. @@ -254,7 +277,7 @@ void synchronize_rcu(void) /* All threads should read qparity before accessing data structure * where new ptr points to. */ /* Write new ptr before changing the qparity */ - cmm_smp_mb(); + smp_mb_master(); /* * Wait for readers to observe original parity or be quiescent. @@ -303,7 +326,7 @@ void synchronize_rcu(void) * Finish waiting for reader threads before letting the old ptr being * freed. */ - cmm_smp_mb(); + smp_mb_master(); out: mutex_unlock(&rcu_registry_lock); mutex_unlock(&rcu_gp_lock); @@ -356,7 +379,7 @@ void expand_arena(struct registry_arena *arena) -1, 0); if (new_chunk == MAP_FAILED) abort(); - bzero(new_chunk, new_chunk_len); + memset(new_chunk, 0, new_chunk_len); new_chunk->data_len = new_chunk_len - sizeof(struct registry_chunk); cds_list_add_tail(&new_chunk->node, &arena->chunk_list); @@ -376,7 +399,7 @@ void expand_arena(struct registry_arena *arena) if (new_chunk != MAP_FAILED) { /* Should not have moved. */ assert(new_chunk == last_chunk); - bzero((char *) last_chunk + old_chunk_len, + memset((char *) last_chunk + old_chunk_len, 0, new_chunk_len - old_chunk_len); last_chunk->data_len = new_chunk_len - sizeof(struct registry_chunk); @@ -390,7 +413,7 @@ void expand_arena(struct registry_arena *arena) -1, 0); if (new_chunk == MAP_FAILED) abort(); - bzero(new_chunk, new_chunk_len); + memset(new_chunk, 0, new_chunk_len); new_chunk->data_len = new_chunk_len - sizeof(struct registry_chunk); cds_list_add_tail(&new_chunk->node, &arena->chunk_list); @@ -567,6 +590,10 @@ void rcu_bp_init(void) urcu_bp_thread_exit_notifier); if (ret) abort(); + ret = membarrier(MEMBARRIER_CMD_QUERY, 0); + if (ret >= 0 && (ret & MEMBARRIER_CMD_SHARED)) { + urcu_bp_has_sys_membarrier = 1; + } initialized = 1; } mutex_unlock(&init_lock);