futex-emulation.h 3.9 KB
Newer Older
binji's avatar
binji committed
1 2 3 4 5 6 7 8 9 10
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_FUTEX_EMULATION_H_
#define V8_FUTEX_EMULATION_H_

#include <stdint.h>

#include "src/allocation.h"
11
#include "src/base/atomicops.h"
binji's avatar
binji committed
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#include "src/base/lazy-instance.h"
#include "src/base/macros.h"
#include "src/base/platform/condition-variable.h"
#include "src/base/platform/mutex.h"
#include "src/handles.h"

// Support for emulating futexes, a low-level synchronization primitive. They
// are natively supported by Linux, but must be emulated for other platforms.
// This library emulates them on all platforms using mutexes and condition
// variables for consistency.
//
// This is used by the Futex API defined in the SharedArrayBuffer draft spec,
// found here: https://github.com/lars-t-hansen/ecmascript_sharedmem

namespace v8 {

namespace base {
class TimeDelta;
}  // base

namespace internal {

class Isolate;
35
class JSArrayBuffer;
binji's avatar
binji committed
36 37 38 39 40 41 42 43

class FutexWaitListNode {
 public:
  FutexWaitListNode()
      : prev_(nullptr),
        next_(nullptr),
        backing_store_(nullptr),
        wait_addr_(0),
44 45 46 47
        waiting_(false),
        interrupted_(false) {}

  void NotifyWake();
binji's avatar
binji committed
48 49 50 51 52 53 54 55 56 57 58

 private:
  friend class FutexEmulation;
  friend class FutexWaitList;

  base::ConditionVariable cond_;
  FutexWaitListNode* prev_;
  FutexWaitListNode* next_;
  void* backing_store_;
  size_t wait_addr_;
  bool waiting_;
59
  bool interrupted_;
binji's avatar
binji committed
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

  DISALLOW_COPY_AND_ASSIGN(FutexWaitListNode);
};


class FutexWaitList {
 public:
  FutexWaitList();

  void AddNode(FutexWaitListNode* node);
  void RemoveNode(FutexWaitListNode* node);

 private:
  friend class FutexEmulation;

  FutexWaitListNode* head_;
  FutexWaitListNode* tail_;

  DISALLOW_COPY_AND_ASSIGN(FutexWaitList);
};


class FutexEmulation : public AllStatic {
 public:
  // These must match the values in src/harmony-atomics.js
  enum Result {
    kOk = 0,
    kNotEqual = -1,
    kTimedOut = -2,
  };

  // Check that array_buffer[addr] == value, and return kNotEqual if not. If
  // they are equal, block execution on |isolate|'s thread until woken via
  // |Wake|, or when the time given in |rel_timeout_ms| elapses. Note that
  // |rel_timeout_ms| can be Infinity.
  // If woken, return kOk, otherwise return kTimedOut. The initial check and
  // the decision to wait happen atomically.
  static Object* Wait(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
                      size_t addr, int32_t value, double rel_timeout_ms);

  // Wake |num_waiters_to_wake| threads that are waiting on the given |addr|.
  // The rest of the waiters will continue to wait. The return value is the
  // number of woken waiters.
  static Object* Wake(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
                      size_t addr, int num_waiters_to_wake);

  // Check that array_buffer[addr] == value, and return kNotEqual if not. If
  // they are equal, wake |num_waiters_to_wake| threads that are waiting on the
  // given |addr|. The rest of the waiters will continue to wait, but will now
  // be waiting on |addr2| instead of |addr|. The return value is the number of
  // woken waiters or kNotEqual as described above.
  static Object* WakeOrRequeue(Isolate* isolate,
                               Handle<JSArrayBuffer> array_buffer, size_t addr,
                               int num_waiters_to_wake, int32_t value,
                               size_t addr2);

  // Return the number of threads waiting on |addr|. Should only be used for
  // testing.
  static Object* NumWaitersForTesting(Isolate* isolate,
                                      Handle<JSArrayBuffer> array_buffer,
                                      size_t addr);

 private:
123 124
  friend class FutexWaitListNode;

binji's avatar
binji committed
125 126 127
  static base::LazyMutex mutex_;
  static base::LazyInstance<FutexWaitList>::type wait_list_;
};
128 129
}  // namespace internal
}  // namespace v8
binji's avatar
binji committed
130 131

#endif  // V8_FUTEX_EMULATION_H_