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