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/tc39/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 // Check that array_buffer[addr] == value, and return "not-equal" if not. If 85 // they are equal, block execution on |isolate|'s thread until woken via 86 // |Wake|, or when the time given in |rel_timeout_ms| elapses. Note that 87 // |rel_timeout_ms| can be Infinity. 88 // If woken, return "ok", otherwise return "timed-out". The initial check and 89 // the decision to wait happen atomically. 90 static Object* Wait(Isolate* isolate, Handle<JSArrayBuffer> array_buffer, 91 size_t addr, int32_t value, double rel_timeout_ms); 92 93 // Wake |num_waiters_to_wake| threads that are waiting on the given |addr|. 94 // The rest of the waiters will continue to wait. The return value is the 95 // number of woken waiters. 96 static Object* Wake(Isolate* isolate, Handle<JSArrayBuffer> array_buffer, 97 size_t addr, int num_waiters_to_wake); 98 99 // Return the number of threads waiting on |addr|. Should only be used for 100 // testing. 101 static Object* NumWaitersForTesting(Isolate* isolate, 102 Handle<JSArrayBuffer> array_buffer, 103 size_t addr); 104 105 private: 106 friend class FutexWaitListNode; 107 108 static base::LazyMutex mutex_; 109 static base::LazyInstance<FutexWaitList>::type wait_list_; 110 }; 111 } // namespace internal 112 } // namespace v8 113 114 #endif // V8_FUTEX_EMULATION_H_ 115