X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=urcu.c;h=e9df01bc7b56cdb25b6e225e6ba46d2182ab28be;hb=2819ef641bb6e2f7aa60c28f3a8f5ad252aa7d00;hp=1d4bf7afb04030155f7cb88d4dcb2cf8e2518a66;hpb=ed42f6768d2116c47ca9ef2c17927a45f6b98f04;p=userspace-rcu.git diff --git a/urcu.c b/urcu.c index 1d4bf7a..e9df01b 100644 --- a/urcu.c +++ b/urcu.c @@ -219,14 +219,40 @@ static void smp_mb_master(int group) /* * synchronize_rcu() waiting. Single thread. + * Always called with rcu_registry lock held. Releases this lock and + * grabs it again. Holds the lock when it returns. */ static void wait_gp(void) { - /* Read reader_gp before read futex */ + /* + * Read reader_gp before read futex. smp_mb_master() needs to + * be called with the rcu registry lock held in RCU_SIGNAL + * flavor. + */ smp_mb_master(RCU_MB_GROUP); - if (uatomic_read(&gp_futex) == -1) - futex_async(&gp_futex, FUTEX_WAIT, -1, - NULL, NULL, 0); + /* Temporarily unlock the registry lock. */ + mutex_unlock(&rcu_registry_lock); + if (uatomic_read(&gp_futex) != -1) + goto end; + while (futex_async(&gp_futex, FUTEX_WAIT, -1, + NULL, NULL, 0)) { + switch (errno) { + case EWOULDBLOCK: + /* Value already changed. */ + goto end; + case EINTR: + /* Retry if interrupted by signal. */ + break; /* Get out of switch. */ + default: + /* Unexpected error. */ + urcu_die(errno); + } + } +end: + /* + * Re-lock the registry lock before the next loop. + */ + mutex_lock(&rcu_registry_lock); } /* @@ -287,14 +313,19 @@ void update_counter_and_wait(void) } break; } else { - /* Temporarily unlock the registry lock. */ - mutex_unlock(&rcu_registry_lock); - if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS) + if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS) { + /* wait_gp unlocks/locks registry lock. */ wait_gp(); - else + } else { + /* Temporarily unlock the registry lock. */ + mutex_unlock(&rcu_registry_lock); caa_cpu_relax(); - /* Re-lock the registry lock before the next loop. */ - mutex_lock(&rcu_registry_lock); + /* + * Re-lock the registry lock before the + * next loop. + */ + mutex_lock(&rcu_registry_lock); + } } #else /* #ifndef HAS_INCOHERENT_CACHES */ /* @@ -314,16 +345,20 @@ void update_counter_and_wait(void) smp_mb_master(RCU_MB_GROUP); wait_gp_loops = 0; } - /* Temporarily unlock the registry lock. */ - mutex_unlock(&rcu_registry_lock); if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS) { + /* wait_gp unlocks/locks registry lock. */ wait_gp(); wait_gp_loops++; } else { + /* Temporarily unlock the registry lock. */ + mutex_unlock(&rcu_registry_lock); caa_cpu_relax(); + /* + * Re-lock the registry lock before the + * next loop. + */ + mutex_lock(&rcu_registry_lock); } - /* Re-lock the registry lock before the next loop. */ - mutex_lock(&rcu_registry_lock); } #endif /* #else #ifndef HAS_INCOHERENT_CACHES */ }