Line data Source code
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 59285 : class FutexWaitListNode {
39 : public:
40 : FutexWaitListNode()
41 : : prev_(nullptr),
42 : next_(nullptr),
43 : backing_store_(nullptr),
44 : wait_addr_(0),
45 : waiting_(false),
46 60782 : 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_
|