• 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 #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 
26 namespace v8 {
27 
28 namespace base {
29 class TimeDelta;
30 }  // base
31 
32 namespace internal {
33 
34 class Isolate;
35 class JSArrayBuffer;
36 
37 class FutexWaitListNode {
38  public:
FutexWaitListNode()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 
65 class 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 
82 class 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_
132