blob: 9949bdf44ff68aef6ef72099aa2a9d8e0f3fb7ea [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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#include "src/handles.h"
17
18// Support for emulating futexes, a low-level synchronization primitive. They
19// are natively supported by Linux, but must be emulated for other platforms.
20// This library emulates them on all platforms using mutexes and condition
21// variables for consistency.
22//
23// This is used by the Futex API defined in the SharedArrayBuffer draft spec,
24// found here: https://github.com/lars-t-hansen/ecmascript_sharedmem
25
26namespace v8 {
27
28namespace base {
29class TimeDelta;
30} // base
31
32namespace internal {
33
34class Isolate;
35class JSArrayBuffer;
36
37class FutexWaitListNode {
38 public:
39 FutexWaitListNode()
40 : prev_(nullptr),
41 next_(nullptr),
42 backing_store_(nullptr),
43 wait_addr_(0),
44 waiting_(false),
45 interrupted_(false) {}
46
47 void NotifyWake();
48
49 private:
50 friend class FutexEmulation;
51 friend class FutexWaitList;
52
53 base::ConditionVariable cond_;
54 FutexWaitListNode* prev_;
55 FutexWaitListNode* next_;
56 void* backing_store_;
57 size_t wait_addr_;
58 bool waiting_;
59 bool interrupted_;
60
61 DISALLOW_COPY_AND_ASSIGN(FutexWaitListNode);
62};
63
64
65class FutexWaitList {
66 public:
67 FutexWaitList();
68
69 void AddNode(FutexWaitListNode* node);
70 void RemoveNode(FutexWaitListNode* node);
71
72 private:
73 friend class FutexEmulation;
74
75 FutexWaitListNode* head_;
76 FutexWaitListNode* tail_;
77
78 DISALLOW_COPY_AND_ASSIGN(FutexWaitList);
79};
80
81
82class FutexEmulation : public AllStatic {
83 public:
84 // These must match the values in src/harmony-atomics.js
85 enum Result {
86 kOk = 0,
87 kNotEqual = -1,
88 kTimedOut = -2,
89 };
90
91 // Check that array_buffer[addr] == value, and return kNotEqual if not. If
92 // they are equal, block execution on |isolate|'s thread until woken via
93 // |Wake|, or when the time given in |rel_timeout_ms| elapses. Note that
94 // |rel_timeout_ms| can be Infinity.
95 // If woken, return kOk, otherwise return kTimedOut. The initial check and
96 // the decision to wait happen atomically.
97 static Object* Wait(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
98 size_t addr, int32_t value, double rel_timeout_ms);
99
100 // Wake |num_waiters_to_wake| threads that are waiting on the given |addr|.
101 // The rest of the waiters will continue to wait. The return value is the
102 // number of woken waiters.
103 static Object* Wake(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
104 size_t addr, int num_waiters_to_wake);
105
106 // Check that array_buffer[addr] == value, and return kNotEqual if not. If
107 // they are equal, wake |num_waiters_to_wake| threads that are waiting on the
108 // given |addr|. The rest of the waiters will continue to wait, but will now
109 // be waiting on |addr2| instead of |addr|. The return value is the number of
110 // woken waiters or kNotEqual as described above.
111 static Object* WakeOrRequeue(Isolate* isolate,
112 Handle<JSArrayBuffer> array_buffer, size_t addr,
113 int num_waiters_to_wake, int32_t value,
114 size_t addr2);
115
116 // Return the number of threads waiting on |addr|. Should only be used for
117 // testing.
118 static Object* NumWaitersForTesting(Isolate* isolate,
119 Handle<JSArrayBuffer> array_buffer,
120 size_t addr);
121
122 private:
123 friend class FutexWaitListNode;
124
125 static base::LazyMutex mutex_;
126 static base::LazyInstance<FutexWaitList>::type wait_list_;
127};
128} // namespace internal
129} // namespace v8
130
131#endif // V8_FUTEX_EMULATION_H_