Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(482)

Side by Side Diff: src/futex-emulation.cc

Issue 1208933006: Atomics Futex API (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: TODO about busy-waiting Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/futex-emulation.h ('k') | src/harmony-atomics.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 #include "src/futex-emulation.h"
6
7 #include <limits>
8
9 #include "src/base/macros.h"
10 #include "src/base/platform/time.h"
11 #include "src/conversions.h"
12 #include "src/handles-inl.h"
13 #include "src/isolate.h"
14 #include "src/list-inl.h"
15
16 namespace v8 {
17 namespace internal {
18
19 base::LazyMutex FutexEmulation::mutex_ = LAZY_MUTEX_INITIALIZER;
20 base::LazyInstance<FutexWaitList>::type FutexEmulation::wait_list_ =
21 LAZY_INSTANCE_INITIALIZER;
22
23
24 FutexWaitList::FutexWaitList() : head_(nullptr), tail_(nullptr) {}
25
26
27 void FutexWaitList::AddNode(FutexWaitListNode* node) {
28 DCHECK(node->prev_ == nullptr && node->next_ == nullptr);
29 if (tail_) {
30 tail_->next_ = node;
31 } else {
32 head_ = node;
33 }
34
35 node->prev_ = tail_;
36 node->next_ = nullptr;
37 tail_ = node;
38 }
39
40
41 void FutexWaitList::RemoveNode(FutexWaitListNode* node) {
42 if (node->prev_) {
43 node->prev_->next_ = node->next_;
44 } else {
45 head_ = node->next_;
46 }
47
48 if (node->next_) {
49 node->next_->prev_ = node->prev_;
50 } else {
51 tail_ = node->prev_;
52 }
53
54 node->prev_ = node->next_ = nullptr;
55 }
56
57
58 Object* FutexEmulation::Wait(Isolate* isolate,
59 Handle<JSArrayBuffer> array_buffer, size_t addr,
60 int32_t value, double rel_timeout_ms) {
61 // We never want to wait longer than this amount of time; this way we can
62 // interrupt this thread even if this is an "infinitely blocking" wait.
63 // TODO(binji): come up with a better way of interrupting only when
64 // necessary, rather than busy-waiting.
65 const base::TimeDelta kMaxWaitTime = base::TimeDelta::FromMilliseconds(50);
66
67 DCHECK(addr < NumberToSize(isolate, array_buffer->byte_length()));
68
69 void* backing_store = array_buffer->backing_store();
70 int32_t* p =
71 reinterpret_cast<int32_t*>(static_cast<int8_t*>(backing_store) + addr);
72
73 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
74
75 if (*p != value) {
76 return Smi::FromInt(Result::kNotEqual);
77 }
78
79 FutexWaitListNode* node = isolate->futex_wait_list_node();
80
81 node->backing_store_ = backing_store;
82 node->wait_addr_ = addr;
83 node->waiting_ = true;
84
85 bool use_timeout = rel_timeout_ms != V8_INFINITY;
86
87 base::TimeDelta rel_timeout;
88 if (use_timeout) {
89 // Convert to nanoseconds.
90 double rel_timeout_ns = rel_timeout_ms *
91 base::Time::kNanosecondsPerMicrosecond *
92 base::Time::kMicrosecondsPerMillisecond;
93 if (rel_timeout_ns >
94 static_cast<double>(std::numeric_limits<int64_t>::max())) {
95 // 2**63 nanoseconds is 292 years. Let's just treat anything greater as
96 // infinite.
97 use_timeout = false;
98 } else {
99 rel_timeout = base::TimeDelta::FromNanoseconds(
100 static_cast<int64_t>(rel_timeout_ns));
101 }
102 }
103
104 base::TimeDelta rel_time_left = rel_timeout;
105
106 wait_list_.Pointer()->AddNode(node);
107
108 Object* result;
109
110 while (true) {
111 base::TimeDelta time_to_wait = (use_timeout && rel_time_left < kMaxWaitTime)
112 ? rel_time_left
113 : kMaxWaitTime;
114
115 base::Time start_time = base::Time::NowFromSystemTime();
116 bool wait_for_result = node->cond_.WaitFor(mutex_.Pointer(), time_to_wait);
117 USE(wait_for_result);
118
119 if (!node->waiting_) {
120 result = Smi::FromInt(Result::kOk);
121 break;
122 }
123
124 // Spurious wakeup or timeout.
125 base::Time end_time = base::Time::NowFromSystemTime();
126 base::TimeDelta waited_for = end_time - start_time;
127 rel_time_left -= waited_for;
128
129 if (use_timeout && rel_time_left < base::TimeDelta::FromMicroseconds(0)) {
130 result = Smi::FromInt(Result::kTimedOut);
131 break;
132 }
133
134 // Potentially handle interrupts before continuing to wait.
135 Object* interrupt_object = isolate->stack_guard()->HandleInterrupts();
136 if (interrupt_object->IsException()) {
137 result = interrupt_object;
138 break;
139 }
140 }
141
142 wait_list_.Pointer()->RemoveNode(node);
143
144 return result;
145 }
146
147
148 Object* FutexEmulation::Wake(Isolate* isolate,
149 Handle<JSArrayBuffer> array_buffer, size_t addr,
150 int num_waiters_to_wake) {
151 DCHECK(addr < NumberToSize(isolate, array_buffer->byte_length()));
152
153 int waiters_woken = 0;
154 void* backing_store = array_buffer->backing_store();
155
156 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
157 FutexWaitListNode* node = wait_list_.Pointer()->head_;
158 while (node && num_waiters_to_wake > 0) {
159 if (backing_store == node->backing_store_ && addr == node->wait_addr_) {
160 node->waiting_ = false;
161 node->cond_.NotifyOne();
162 --num_waiters_to_wake;
163 waiters_woken++;
164 }
165
166 node = node->next_;
167 }
168
169 return Smi::FromInt(waiters_woken);
170 }
171
172
173 Object* FutexEmulation::WakeOrRequeue(Isolate* isolate,
174 Handle<JSArrayBuffer> array_buffer,
175 size_t addr, int num_waiters_to_wake,
176 int32_t value, size_t addr2) {
177 DCHECK(addr < NumberToSize(isolate, array_buffer->byte_length()));
178 DCHECK(addr2 < NumberToSize(isolate, array_buffer->byte_length()));
179
180 void* backing_store = array_buffer->backing_store();
181 int32_t* p =
182 reinterpret_cast<int32_t*>(static_cast<int8_t*>(backing_store) + addr);
183
184 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
185 if (*p != value) {
186 return Smi::FromInt(Result::kNotEqual);
187 }
188
189 // Wake |num_waiters_to_wake|
190 int waiters_woken = 0;
191 FutexWaitListNode* node = wait_list_.Pointer()->head_;
192 while (node) {
193 if (backing_store == node->backing_store_ && addr == node->wait_addr_) {
194 if (num_waiters_to_wake > 0) {
195 node->waiting_ = false;
196 node->cond_.NotifyOne();
197 --num_waiters_to_wake;
198 waiters_woken++;
199 } else {
200 node->wait_addr_ = addr2;
201 }
202 }
203
204 node = node->next_;
205 }
206
207 return Smi::FromInt(waiters_woken);
208 }
209
210
211 Object* FutexEmulation::NumWaitersForTesting(Isolate* isolate,
212 Handle<JSArrayBuffer> array_buffer,
213 size_t addr) {
214 DCHECK(addr < NumberToSize(isolate, array_buffer->byte_length()));
215 void* backing_store = array_buffer->backing_store();
216
217 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
218
219 int waiters = 0;
220 FutexWaitListNode* node = wait_list_.Pointer()->head_;
221 while (node) {
222 if (backing_store == node->backing_store_ && addr == node->wait_addr_) {
223 waiters++;
224 }
225
226 node = node->next_;
227 }
228
229 return Smi::FromInt(waiters);
230 }
231
232 } // namespace internal
233 } // namespace v8
OLDNEW
« no previous file with comments | « src/futex-emulation.h ('k') | src/harmony-atomics.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698