Home | History | Annotate | Download | only in src
      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:
     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