• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
38 class FutexWaitListNode {
39  public:
FutexWaitListNode()40   FutexWaitListNode()
41       : prev_(nullptr),
42         next_(nullptr),
43         backing_store_(nullptr),
44         wait_addr_(0),
45         waiting_(false),
46         interrupted_(false) {}
47 
48   void NotifyWake();
49 
50  private:
51   friend class FutexEmulation;
52   friend class FutexWaitList;
53 
54   base::ConditionVariable cond_;
55   FutexWaitListNode* prev_;
56   FutexWaitListNode* next_;
57   void* backing_store_;
58   size_t wait_addr_;
59   bool waiting_;
60   bool interrupted_;
61 
62   DISALLOW_COPY_AND_ASSIGN(FutexWaitListNode);
63 };
64 
65 
66 class FutexWaitList {
67  public:
68   FutexWaitList();
69 
70   void AddNode(FutexWaitListNode* node);
71   void RemoveNode(FutexWaitListNode* node);
72 
73  private:
74   friend class FutexEmulation;
75 
76   FutexWaitListNode* head_;
77   FutexWaitListNode* tail_;
78 
79   DISALLOW_COPY_AND_ASSIGN(FutexWaitList);
80 };
81 
82 
83 class FutexEmulation : public AllStatic {
84  public:
85   // Pass to Wake() to wake all waiters.
86   static const uint32_t kWakeAll = UINT32_MAX;
87 
88   // Check that array_buffer[addr] == value, and return "not-equal" if not. If
89   // they are equal, block execution on |isolate|'s thread until woken via
90   // |Wake|, or when the time given in |rel_timeout_ms| elapses. Note that
91   // |rel_timeout_ms| can be Infinity.
92   // If woken, return "ok", otherwise return "timed-out". The initial check and
93   // the decision to wait happen atomically.
94   static Object* Wait(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
95                       size_t addr, int32_t value, double rel_timeout_ms);
96 
97   // Wake |num_waiters_to_wake| threads that are waiting on the given |addr|.
98   // |num_waiters_to_wake| can be kWakeAll, in which case all waiters are
99   // woken. The rest of the waiters will continue to wait. The return value is
100   // the number of woken waiters.
101   static Object* Wake(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
102                       size_t addr, uint32_t num_waiters_to_wake);
103 
104   // Return the number of threads waiting on |addr|. Should only be used for
105   // testing.
106   static Object* NumWaitersForTesting(Isolate* isolate,
107                                       Handle<JSArrayBuffer> array_buffer,
108                                       size_t addr);
109 
110  private:
111   friend class FutexWaitListNode;
112 
113   static base::LazyMutex mutex_;
114   static base::LazyInstance<FutexWaitList>::type wait_list_;
115 };
116 }  // namespace internal
117 }  // namespace v8
118 
119 #endif  // V8_FUTEX_EMULATION_H_
120