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