X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Fsynchronization%2FBaton.h;h=379f9021f646e939e4cdc485491f3b37c537ba3f;hb=712b8b8de747960ceeceedfd3a18ee23a0c03a80;hp=ef87125286723f6aad8fd4daf7ed6d50b0178681;hpb=90ce64f987677e11200729afa6bb9c4b64caf01e;p=folly.git diff --git a/folly/synchronization/Baton.h b/folly/synchronization/Baton.h index ef871252..379f9021 100644 --- a/folly/synchronization/Baton.h +++ b/folly/synchronization/Baton.h @@ -29,22 +29,16 @@ namespace folly { -/// A Baton allows a thread to block once and be awoken. The single -/// poster version (with SinglePoster == true) captures a single -/// handoff, and during its lifecycle (from construction/reset to -/// destruction/reset) a baton must either be post()ed and wait()ed +/// A Baton allows a thread to block once and be awoken. Captures a +/// single handoff, and during its lifecycle (from construction/reset +/// to destruction/reset) a baton must either be post()ed and wait()ed /// exactly once each, or not at all. /// -/// The multi-poster version (SinglePoster == false) allows multiple -/// concurrent handoff attempts, the first of which completes the -/// handoff and the rest if any are idempotent. -/// /// Baton includes no internal padding, and is only 4 bytes in size. /// Any alignment or padding to avoid false sharing is up to the user. /// -/// This is basically a stripped-down semaphore that supports (only a -/// single call to sem_post, when SinglePoster == true) and a single -/// call to sem_wait. +/// This is basically a stripped-down semaphore that supports only a +/// single call to sem_post and a single call to sem_wait. /// /// The non-blocking version (Blocking == false) provides more speed /// by using only load acquire and store release operations in the @@ -58,7 +52,6 @@ namespace folly { /// catch race conditions ahead of time. template < template class Atom = std::atomic, - bool SinglePoster = true, // single vs multiple posters bool Blocking = true> // blocking vs spinning struct Baton { constexpr Baton() : state_(INIT) {} @@ -130,65 +123,24 @@ struct Baton { /// Blocking versions /// - if (SinglePoster) { - /// Single poster version - /// - uint32_t before = state_.load(std::memory_order_acquire); + uint32_t before = state_.load(std::memory_order_acquire); - assert(before == INIT || before == WAITING || before == TIMED_OUT); + assert(before == INIT || before == WAITING || before == TIMED_OUT); - if (before == INIT && - state_.compare_exchange_strong(before, EARLY_DELIVERY)) { - return; - } - - assert(before == WAITING || before == TIMED_OUT); + if (before == INIT && + state_.compare_exchange_strong(before, EARLY_DELIVERY)) { + return; + } - if (before == TIMED_OUT) { - return; - } + assert(before == WAITING || before == TIMED_OUT); - assert(before == WAITING); - state_.store(LATE_DELIVERY, std::memory_order_release); - state_.futexWake(1); - } else { - /// Multi-poster version - /// - while (true) { - uint32_t before = state_.load(std::memory_order_acquire); - - if (before == INIT && - state_.compare_exchange_strong(before, EARLY_DELIVERY)) { - return; - } - - if (before == TIMED_OUT) { - return; - } - - if (before == EARLY_DELIVERY || before == LATE_DELIVERY) { - // The reason for not simply returning (without the following - // atomic operation) is to avoid the following case: - // - // T1: T2: T3: - // local1.post(); local2.post(); global.wait(); - // global.post(); global.post(); local1.try_wait() == true; - // local2.try_wait() == false; - // - if (state_.fetch_add(0) != before) { - continue; - } - return; - } - - assert(before == WAITING); - if (!state_.compare_exchange_weak(before, LATE_DELIVERY)) { - continue; - } - state_.futexWake(1); - return; - } + if (before == TIMED_OUT) { + return; } + + assert(before == WAITING); + state_.store(LATE_DELIVERY, std::memory_order_release); + state_.futexWake(1); } /// Waits until post() has been called in the current Baton lifetime.