1014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Copyright 2015 the V8 project authors. All rights reserved.
2014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// found in the LICENSE file.
4014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/futex-emulation.h"
6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
7014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include <limits>
8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/base/macros.h"
10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/base/platform/time.h"
11014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/conversions.h"
12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/handles-inl.h"
13014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/isolate.h"
14014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/list-inl.h"
1562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/objects-inl.h"
16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
17014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace v8 {
18014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace internal {
19014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
20014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochbase::LazyMutex FutexEmulation::mutex_ = LAZY_MUTEX_INITIALIZER;
21014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochbase::LazyInstance<FutexWaitList>::type FutexEmulation::wait_list_ =
22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    LAZY_INSTANCE_INITIALIZER;
23014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
24014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
25014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid FutexWaitListNode::NotifyWake() {
26014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Lock the FutexEmulation mutex before notifying. We know that the mutex
27014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // will have been unlocked if we are currently waiting on the condition
28014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // variable.
29014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //
30014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // The mutex may also not be locked if the other thread is currently handling
31014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // interrupts, or if FutexEmulation::Wait was just called and the mutex
32014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // hasn't been locked yet. In either of those cases, we set the interrupted
33014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // flag to true, which will be tested after the mutex is re-locked.
34014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  base::LockGuard<base::Mutex> lock_guard(FutexEmulation::mutex_.Pointer());
35014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (waiting_) {
36014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    cond_.NotifyOne();
37014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    interrupted_ = true;
38014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
39014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
40014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
41014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
42014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochFutexWaitList::FutexWaitList() : head_(nullptr), tail_(nullptr) {}
43014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
44014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
45014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid FutexWaitList::AddNode(FutexWaitListNode* node) {
46014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK(node->prev_ == nullptr && node->next_ == nullptr);
47014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (tail_) {
48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    tail_->next_ = node;
49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else {
50014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    head_ = node;
51014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
52014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
53014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  node->prev_ = tail_;
54014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  node->next_ = nullptr;
55014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  tail_ = node;
56014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
57014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
58014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
59014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid FutexWaitList::RemoveNode(FutexWaitListNode* node) {
60014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (node->prev_) {
61014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->prev_->next_ = node->next_;
62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else {
63014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    head_ = node->next_;
64014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
65014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
66014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (node->next_) {
67014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->next_->prev_ = node->prev_;
68014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else {
69014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    tail_ = node->prev_;
70014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
71014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
72014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  node->prev_ = node->next_ = nullptr;
73014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
74014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
75014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
76014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochObject* FutexEmulation::Wait(Isolate* isolate,
77014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                             Handle<JSArrayBuffer> array_buffer, size_t addr,
78014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                             int32_t value, double rel_timeout_ms) {
79f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  DCHECK(addr < NumberToSize(array_buffer->byte_length()));
80014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
81014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  void* backing_store = array_buffer->backing_store();
82014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int32_t* p =
83014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      reinterpret_cast<int32_t*>(static_cast<int8_t*>(backing_store) + addr);
84014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
85014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
87014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (*p != value) {
88f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    return isolate->heap()->not_equal();
89014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
91014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  FutexWaitListNode* node = isolate->futex_wait_list_node();
92014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  node->backing_store_ = backing_store;
94014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  node->wait_addr_ = addr;
95014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  node->waiting_ = true;
96014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  bool use_timeout = rel_timeout_ms != V8_INFINITY;
98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
99014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  base::TimeDelta rel_timeout;
100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (use_timeout) {
101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Convert to nanoseconds.
102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    double rel_timeout_ns = rel_timeout_ms *
103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                            base::Time::kNanosecondsPerMicrosecond *
104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                            base::Time::kMicrosecondsPerMillisecond;
105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (rel_timeout_ns >
106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        static_cast<double>(std::numeric_limits<int64_t>::max())) {
107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // 2**63 nanoseconds is 292 years. Let's just treat anything greater as
108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // infinite.
109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      use_timeout = false;
110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else {
111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      rel_timeout = base::TimeDelta::FromNanoseconds(
112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          static_cast<int64_t>(rel_timeout_ns));
113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  base::TimeTicks start_time = base::TimeTicks::Now();
117014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  base::TimeTicks timeout_time = start_time + rel_timeout;
118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  base::TimeTicks current_time = start_time;
119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  wait_list_.Pointer()->AddNode(node);
121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Object* result;
123014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
124014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  while (true) {
125014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    bool interrupted = node->interrupted_;
126014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->interrupted_ = false;
127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Unlock the mutex here to prevent deadlock from lock ordering between
129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // mutex_ and mutexes locked by HandleInterrupts.
130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    mutex_.Pointer()->Unlock();
131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
132014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Because the mutex is unlocked, we have to be careful about not dropping
133014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // an interrupt. The notification can happen in three different places:
134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // 1) Before Wait is called: the notification will be dropped, but
135014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //    interrupted_ will be set to 1. This will be checked below.
136014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // 2) After interrupted has been checked here, but before mutex_ is
137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //    acquired: interrupted is checked again below, with mutex_ locked.
138014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //    Because the wakeup signal also acquires mutex_, we know it will not
139014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //    be able to notify until mutex_ is released below, when waiting on the
140014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    //    condition variable.
141014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // 3) After the mutex is released in the call to WaitFor(): this
142014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // notification will wake up the condition variable. node->waiting() will
143014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // be false, so we'll loop and then check interrupts.
144014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (interrupted) {
145014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Object* interrupt_object = isolate->stack_guard()->HandleInterrupts();
14613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (interrupt_object->IsException(isolate)) {
147014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        result = interrupt_object;
148014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        mutex_.Pointer()->Lock();
149014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        break;
150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
152014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
153014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    mutex_.Pointer()->Lock();
154014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
155014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (node->interrupted_) {
156014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // An interrupt occured while the mutex_ was unlocked. Don't wait yet.
157014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      continue;
158014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
159014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
160014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!node->waiting_) {
161f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result = isolate->heap()->ok();
162014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      break;
163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
164014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // No interrupts, now wait.
166014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (use_timeout) {
167014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      current_time = base::TimeTicks::Now();
168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (current_time >= timeout_time) {
169f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        result = isolate->heap()->timed_out();
170014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        break;
171014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
172014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
173014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      base::TimeDelta time_until_timeout = timeout_time - current_time;
174014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      DCHECK(time_until_timeout.InMicroseconds() >= 0);
175014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      bool wait_for_result =
176014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          node->cond_.WaitFor(mutex_.Pointer(), time_until_timeout);
177014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      USE(wait_for_result);
178014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else {
179014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      node->cond_.Wait(mutex_.Pointer());
180014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
182014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Spurious wakeup, interrupt or timeout.
183014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  wait_list_.Pointer()->RemoveNode(node);
186014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  node->waiting_ = false;
187014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
188014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return result;
189014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
190014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
191014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochObject* FutexEmulation::Wake(Isolate* isolate,
192014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                             Handle<JSArrayBuffer> array_buffer, size_t addr,
19362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                             uint32_t num_waiters_to_wake) {
194f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  DCHECK(addr < NumberToSize(array_buffer->byte_length()));
195014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
196014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int waiters_woken = 0;
197014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  void* backing_store = array_buffer->backing_store();
198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  FutexWaitListNode* node = wait_list_.Pointer()->head_;
201014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  while (node && num_waiters_to_wake > 0) {
202014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (backing_store == node->backing_store_ && addr == node->wait_addr_) {
203014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      node->waiting_ = false;
204014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      node->cond_.NotifyOne();
20562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      if (num_waiters_to_wake != kWakeAll) {
20662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        --num_waiters_to_wake;
20762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      }
208014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      waiters_woken++;
209014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
210014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
211014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node = node->next_;
212014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
213014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
214014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return Smi::FromInt(waiters_woken);
215014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
216014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
217014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
218014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochObject* FutexEmulation::NumWaitersForTesting(Isolate* isolate,
219014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                             Handle<JSArrayBuffer> array_buffer,
220014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                             size_t addr) {
221f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  DCHECK(addr < NumberToSize(array_buffer->byte_length()));
222014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  void* backing_store = array_buffer->backing_store();
223014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
224014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
225014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
226014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int waiters = 0;
227014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  FutexWaitListNode* node = wait_list_.Pointer()->head_;
228014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  while (node) {
229014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (backing_store == node->backing_store_ && addr == node->wait_addr_ &&
230014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        node->waiting_) {
231014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      waiters++;
232014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
233014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
234014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node = node->next_;
235014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
236014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
237014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return Smi::FromInt(waiters);
238014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
239014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
240014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
242