From: Mathieu Desnoyers Date: Mon, 9 Feb 2009 05:54:50 +0000 (-0500) Subject: Use xchg in publish content X-Git-Tag: v0.1~312 X-Git-Url: https://git.lttng.org/?p=urcu.git;a=commitdiff_plain;h=f4a486ac095bd844d0c18995737d589b8f085b69 Use xchg in publish content Also changes the publish content parameter. Now takes the pointer itself as first parameter rather than a pointer to the pointer. Signed-off-by: Mathieu Desnoyers --- diff --git a/test_urcu.c b/test_urcu.c index 39408a0..b92a7d7 100644 --- a/test_urcu.c +++ b/test_urcu.c @@ -127,7 +127,7 @@ void *thr_writer(void *arg) if (old) assert(old->a == 8); new->a = 8; - old = urcu_publish_content((void **)&test_rcu_pointer, new); + old = urcu_publish_content(&test_rcu_pointer, new); rcu_copy_mutex_unlock(); /* can be done after unlock */ if (old) diff --git a/test_urcu_timing.c b/test_urcu_timing.c index 9903705..f97a5c1 100644 --- a/test_urcu_timing.c +++ b/test_urcu_timing.c @@ -145,7 +145,7 @@ void *thr_writer(void *arg) assert(old->a == 8); } new->a = 8; - old = urcu_publish_content((void **)&test_rcu_pointer, new); + old = urcu_publish_content(&test_rcu_pointer, new); rcu_copy_mutex_unlock(); /* can be done after unlock */ if (old) { diff --git a/urcu.c b/urcu.c index 23a985b..9fde623 100644 --- a/urcu.c +++ b/urcu.c @@ -151,42 +151,6 @@ void synchronize_rcu(void) debug_yield_write(); } -/* - * Return old pointer, OK to free, no more reference exist. - * Called under rcu_write_lock. - */ -void *urcu_publish_content(void **ptr, void *new) -{ - void *oldptr; - - debug_yield_write(); - internal_urcu_lock(); - debug_yield_write(); - /* - * We can publish the new pointer before we change the current qparity. - * Readers seeing the new pointer while being in the previous qparity - * window will make us wait until the end of the quiescent state before - * we release the unrelated memory area. However, given we hold the - * urcu_mutex, we are making sure that no further garbage collection can - * occur until we release the mutex, therefore we guarantee that this - * given reader will have completed its execution using the new pointer - * when the next quiescent state window will be over. - */ - oldptr = *ptr; - debug_yield_write(); - rcu_assign_pointer(*ptr, new); - - debug_yield_write(); - switch_qparity(); - debug_yield_write(); - switch_qparity(); - debug_yield_write(); - internal_urcu_unlock(); - debug_yield_write(); - - return oldptr; -} - void urcu_add_reader(pthread_t id) { struct reader_data *oldarray; diff --git a/urcu.h b/urcu.h index 27695d4..fb8cedf 100644 --- a/urcu.h +++ b/urcu.h @@ -33,6 +33,45 @@ static inline void atomic_inc(int *v) : "+m" (*v)); } +#define xchg(ptr, v) \ + ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), sizeof(*(ptr)))) + +struct __xchg_dummy { + unsigned long a[100]; +}; +#define __xg(x) ((struct __xchg_dummy *)(x)) + +/* + * Note: no "lock" prefix even on SMP: xchg always implies lock anyway + * Note 2: xchg has side effect, so that attribute volatile is necessary, + * but generally the primitive is invalid, *ptr is output argument. --ANK + */ +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + switch (size) { + case 1: + asm volatile("xchgb %b0,%1" + : "=q" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 2: + asm volatile("xchgw %w0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 4: + asm volatile("xchgl %0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + } + return x; +} + /* Nop everywhere except on alpha. */ #define smp_read_barrier_depends() @@ -190,9 +229,29 @@ static inline void rcu_read_unlock(void) (p) = (v); \ }) -extern void *urcu_publish_content(void **ptr, void *new); +#define rcu_xchg_pointer(p, v) \ + ({ \ + if (!__builtin_constant_p(v) || \ + ((v) != NULL)) \ + wmb(); \ + xchg(p, v); \ + }) + extern void synchronize_rcu(void); +/* + * Exchanges the pointer and waits for quiescent state. + * The pointer returned can be freed. + */ +#define urcu_publish_content(p, v) \ + ({ \ + void *oldptr; \ + debug_yield_write(); \ + oldptr = rcu_xchg_pointer(p, v); \ + synchronize_rcu(); \ + oldptr; \ + }) + /* * Reader thread registration. */