V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
futex-emulation.h
1 // Copyright 2015 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_FUTEX_EMULATION_H_
6 #define V8_FUTEX_EMULATION_H_
7 
8 #include <stdint.h>
9 
10 #include "src/allocation.h"
11 #include "src/base/atomicops.h"
12 #include "src/base/lazy-instance.h"
13 #include "src/base/macros.h"
14 #include "src/base/platform/condition-variable.h"
15 #include "src/base/platform/mutex.h"
16 
17 // Support for emulating futexes, a low-level synchronization primitive. They
18 // are natively supported by Linux, but must be emulated for other platforms.
19 // This library emulates them on all platforms using mutexes and condition
20 // variables for consistency.
21 //
22 // This is used by the Futex API defined in the SharedArrayBuffer draft spec,
23 // found here: https://github.com/tc39/ecmascript_sharedmem
24 
25 namespace v8 {
26 
27 namespace base {
28 class TimeDelta;
29 } // base
30 
31 namespace internal {
32 
33 template <typename T>
34 class Handle;
35 class Isolate;
36 class JSArrayBuffer;
37 
39  public:
40  explicit AtomicsWaitWakeHandle(Isolate* isolate) : isolate_(isolate) {}
41 
42  void Wake();
43  inline bool has_stopped() const { return stopped_; }
44 
45  private:
46  Isolate* isolate_;
47  bool stopped_ = false;
48 };
49 
51  public:
53  : prev_(nullptr),
54  next_(nullptr),
55  backing_store_(nullptr),
56  wait_addr_(0),
57  waiting_(false),
58  interrupted_(false) {}
59 
60  void NotifyWake();
61 
62  private:
63  friend class FutexEmulation;
64  friend class FutexWaitList;
65  friend class ResetWaitingOnScopeExit;
66 
68  // prev_ and next_ are protected by FutexEmulation::mutex_.
69  FutexWaitListNode* prev_;
70  FutexWaitListNode* next_;
71  void* backing_store_;
72  size_t wait_addr_;
73  // waiting_ and interrupted_ are protected by FutexEmulation::mutex_
74  // if this node is currently contained in FutexEmulation::wait_list_
75  // or an AtomicsWaitWakeHandle has access to it.
76  bool waiting_;
77  bool interrupted_;
78 
79  DISALLOW_COPY_AND_ASSIGN(FutexWaitListNode);
80 };
81 
82 
84  public:
85  FutexWaitList();
86 
87  void AddNode(FutexWaitListNode* node);
88  void RemoveNode(FutexWaitListNode* node);
89 
90  private:
91  friend class FutexEmulation;
92 
93  FutexWaitListNode* head_;
94  FutexWaitListNode* tail_;
95 
96  DISALLOW_COPY_AND_ASSIGN(FutexWaitList);
97 };
98 
100  public:
101  explicit ResetWaitingOnScopeExit(FutexWaitListNode* node) : node_(node) {}
102  ~ResetWaitingOnScopeExit() { node_->waiting_ = false; }
103 
104  private:
105  FutexWaitListNode* node_;
106 
107  DISALLOW_COPY_AND_ASSIGN(ResetWaitingOnScopeExit);
108 };
109 
110 class FutexEmulation : public AllStatic {
111  public:
112  // Pass to Wake() to wake all waiters.
113  static const uint32_t kWakeAll = UINT32_MAX;
114 
115  // Check that array_buffer[addr] == value, and return "not-equal" if not. If
116  // they are equal, block execution on |isolate|'s thread until woken via
117  // |Wake|, or when the time given in |rel_timeout_ms| elapses. Note that
118  // |rel_timeout_ms| can be Infinity.
119  // If woken, return "ok", otherwise return "timed-out". The initial check and
120  // the decision to wait happen atomically.
121  static Object* WaitJs(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
122  size_t addr, int32_t value, double rel_timeout_ms);
123 
124  // Same as WaitJs above except it returns 0 (ok), 1 (not equal) and 2 (timed
125  // out) as expected by Wasm.
126  static Object* Wait(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
127  size_t addr, int32_t value, double rel_timeout_ms);
128 
129  // Wake |num_waiters_to_wake| threads that are waiting on the given |addr|.
130  // |num_waiters_to_wake| can be kWakeAll, in which case all waiters are
131  // woken. The rest of the waiters will continue to wait. The return value is
132  // the number of woken waiters.
133  static Object* Wake(Handle<JSArrayBuffer> array_buffer, size_t addr,
134  uint32_t num_waiters_to_wake);
135 
136  // Return the number of threads waiting on |addr|. Should only be used for
137  // testing.
138  static Object* NumWaitersForTesting(Handle<JSArrayBuffer> array_buffer,
139  size_t addr);
140 
141  private:
142  friend class FutexWaitListNode;
143  friend class AtomicsWaitWakeHandle;
144 
145  // `mutex_` protects the composition of `wait_list_` (i.e. no elements may be
146  // added or removed without holding this mutex), as well as the `waiting_`
147  // and `interrupted_` fields for each individual list node that is currently
148  // part of the list. It must be the mutex used together with the `cond_`
149  // condition variable of such nodes.
150  static base::LazyMutex mutex_;
151  static base::LazyInstance<FutexWaitList>::type wait_list_;
152 };
153 } // namespace internal
154 } // namespace v8
155 
156 #endif // V8_FUTEX_EMULATION_H_
Definition: libplatform.h:13