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