1e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// Copyright 2013 the V8 project authors. All rights reserved. 23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// Use of this source code is governed by a BSD-style license that can be 33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// found in the LICENSE file. 4e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 55de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#ifndef V8_BASE_PLATFORM_CONDITION_VARIABLE_H_ 65de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#define V8_BASE_PLATFORM_CONDITION_VARIABLE_H_ 7e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 81e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/lazy-instance.h" 95de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#include "src/base/platform/mutex.h" 10e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 11e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgnamespace v8 { 125de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.orgnamespace base { 13e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 14e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// Forward declarations. 15e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgclass ConditionVariableEvent; 16e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgclass TimeDelta; 17e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 18e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// ----------------------------------------------------------------------------- 19e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// ConditionVariable 20e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// 21e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// This class is a synchronization primitive that can be used to block a thread, 22e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// or multiple threads at the same time, until: 23e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// - a notification is received from another thread, 24e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// - a timeout expires, or 25e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// - a spurious wakeup occurs 26e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// Any thread that intends to wait on a ConditionVariable has to acquire a lock 27e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// on a Mutex first. The |Wait()| and |WaitFor()| operations atomically release 28e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// the mutex and suspend the execution of the calling thread. When the condition 29e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// variable is notified, the thread is awakened, and the mutex is reacquired. 30e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 31ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.orgclass ConditionVariable FINAL { 32e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org public: 33e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org ConditionVariable(); 34e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org ~ConditionVariable(); 35e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 36e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // If any threads are waiting on this condition variable, calling 37e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // |NotifyOne()| unblocks one of the waiting threads. 38e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org void NotifyOne(); 39e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 40e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // Unblocks all threads currently waiting for this condition variable. 41e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org void NotifyAll(); 42e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 43e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // |Wait()| causes the calling thread to block until the condition variable is 44e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // notified or a spurious wakeup occurs. Atomically releases the mutex, blocks 45e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // the current executing thread, and adds it to the list of threads waiting on 46e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // this condition variable. The thread will be unblocked when |NotifyAll()| or 47e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // |NotifyOne()| is executed. It may also be unblocked spuriously. When 48e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // unblocked, regardless of the reason, the lock on the mutex is reacquired 49e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // and |Wait()| exits. 50e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org void Wait(Mutex* mutex); 51e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 52e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // Atomically releases the mutex, blocks the current executing thread, and 53e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // adds it to the list of threads waiting on this condition variable. The 54e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // thread will be unblocked when |NotifyAll()| or |NotifyOne()| is executed, 55e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // or when the relative timeout |rel_time| expires. It may also be unblocked 56e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // spuriously. When unblocked, regardless of the reason, the lock on the mutex 57e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // is reacquired and |WaitFor()| exits. Returns true if the condition variable 58e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // was notified prior to the timeout. 59ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org bool WaitFor(Mutex* mutex, const TimeDelta& rel_time) WARN_UNUSED_RESULT; 60e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 61e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org // The implementation-defined native handle type. 62e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#if V8_OS_POSIX 63e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org typedef pthread_cond_t NativeHandle; 64e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#elif V8_OS_WIN 65e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org struct Event; 66ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org class NativeHandle FINAL { 67e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org public: 68e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org NativeHandle() : waitlist_(NULL), freelist_(NULL) {} 69e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org ~NativeHandle(); 70e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 71ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org Event* Pre() WARN_UNUSED_RESULT; 72e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org void Post(Event* event, bool result); 73e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 74e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org Mutex* mutex() { return &mutex_; } 75e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org Event* waitlist() { return waitlist_; } 76e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 77e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private: 78e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org Event* waitlist_; 79e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org Event* freelist_; 80e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org Mutex mutex_; 81e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 82e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org DISALLOW_COPY_AND_ASSIGN(NativeHandle); 83e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org }; 84e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#endif 85e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 86c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org NativeHandle& native_handle() { 87e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org return native_handle_; 88e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org } 89c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org const NativeHandle& native_handle() const { 90e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org return native_handle_; 91e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org } 92e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 93e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private: 94e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org NativeHandle native_handle_; 95e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 96e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org DISALLOW_COPY_AND_ASSIGN(ConditionVariable); 97e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org}; 98e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 99e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 100e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// POD ConditionVariable initialized lazily (i.e. the first time Pointer() is 101e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// called). 102e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// Usage: 103e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// static LazyConditionVariable my_condvar = 104e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// LAZY_CONDITION_VARIABLE_INITIALIZER; 105e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// 106e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// void my_function() { 107e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// LockGuard<Mutex> lock_guard(&my_mutex); 108e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// my_condvar.Pointer()->Wait(&my_mutex); 109e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org// } 1105de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.orgtypedef LazyStaticInstance< 1115de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org ConditionVariable, DefaultConstructTrait<ConditionVariable>, 1125de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org ThreadSafeInitOnceTrait>::type LazyConditionVariable; 113e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 114e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org#define LAZY_CONDITION_VARIABLE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER 115e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 1165de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org} } // namespace v8::base 117e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 1185de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#endif // V8_BASE_PLATFORM_CONDITION_VARIABLE_H_ 119