155 lines
5.7 KiB
C++
155 lines
5.7 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef builtin_AtomicsObject_h
|
|
#define builtin_AtomicsObject_h
|
|
|
|
#include "mozilla/Maybe.h"
|
|
#include "mozilla/TimeStamp.h"
|
|
|
|
#include "jsobj.h"
|
|
|
|
#include "threading/ConditionVariable.h"
|
|
#include "vm/MutexIDs.h"
|
|
|
|
namespace js {
|
|
|
|
class AtomicsObject : public JSObject
|
|
{
|
|
public:
|
|
static const Class class_;
|
|
static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
|
|
static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
|
|
};
|
|
|
|
MOZ_MUST_USE bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_load(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_store(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_add(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_sub(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_and(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
|
|
MOZ_MUST_USE bool atomics_notify(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/* asm.js callouts */
|
|
namespace wasm { class Instance; }
|
|
int32_t atomics_add_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
|
|
int32_t atomics_sub_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
|
|
int32_t atomics_and_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
|
|
int32_t atomics_or_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
|
|
int32_t atomics_xor_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
|
|
int32_t atomics_cmpxchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t oldval, int32_t newval);
|
|
int32_t atomics_xchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
|
|
|
|
class FutexRuntime
|
|
{
|
|
friend class AutoLockFutexAPI;
|
|
|
|
public:
|
|
static MOZ_MUST_USE bool initialize();
|
|
static void destroy();
|
|
|
|
static void lock();
|
|
static void unlock();
|
|
|
|
FutexRuntime();
|
|
MOZ_MUST_USE bool initInstance();
|
|
void destroyInstance();
|
|
|
|
// Parameters to notify().
|
|
enum NotifyReason {
|
|
NotifyExplicit, // Being asked to wake up by another thread
|
|
NotifyForJSInterrupt // Interrupt requested
|
|
};
|
|
|
|
// Result code from wait().
|
|
enum WaitResult {
|
|
FutexOK,
|
|
FutexTimedOut
|
|
};
|
|
|
|
// Block the calling thread and wait.
|
|
//
|
|
// The futex lock must be held around this call.
|
|
//
|
|
// The timeout is the number of milliseconds, with fractional
|
|
// times allowed; specify mozilla::Nothing() for an indefinite
|
|
// wait.
|
|
//
|
|
// wait() will not wake up spuriously.
|
|
MOZ_MUST_USE bool wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
|
|
mozilla::Maybe<mozilla::TimeDuration>& timeout, WaitResult* result);
|
|
|
|
// Notify the thread represented by this Runtime.
|
|
//
|
|
// The futex lock must be held around this call. (The sleeping
|
|
// thread will not wake up until the caller of Atomics.notify()
|
|
// releases the lock.)
|
|
//
|
|
// If the thread is not waiting then this method does nothing.
|
|
//
|
|
// If the thread is waiting in a call to wait() and the
|
|
// reason is NotifyExplicit then the wait() call will return
|
|
// with Woken.
|
|
//
|
|
// If the thread is waiting in a call to wait() and the
|
|
// reason is NotifyForJSInterrupt then the wait() will return
|
|
// with WaitingNotifiedForInterrupt; in the latter case the caller
|
|
// of wait() must handle the interrupt.
|
|
void notify(NotifyReason reason);
|
|
|
|
bool isWaiting();
|
|
|
|
// If canWait() returns false (the default) then wait() is disabled
|
|
// on the runtime to which the FutexRuntime belongs.
|
|
bool canWait() {
|
|
return canWait_;
|
|
}
|
|
|
|
void setCanWait(bool flag) {
|
|
canWait_ = flag;
|
|
}
|
|
|
|
private:
|
|
enum FutexState {
|
|
Idle, // We are not waiting or woken
|
|
Waiting, // We are waiting, nothing has happened yet
|
|
WaitingNotifiedForInterrupt, // We are waiting, but have been interrupted,
|
|
// and have not yet started running the
|
|
// interrupt handler
|
|
WaitingInterrupted, // We are waiting, but have been interrupted
|
|
// and are running the interrupt handler
|
|
Woken // Woken by a script call to Atomics.notify
|
|
};
|
|
|
|
// Condition variable that this runtime will wait on.
|
|
js::ConditionVariable* cond_;
|
|
|
|
// Current futex state for this runtime. When not in a wait this
|
|
// is Idle; when in a wait it is Waiting or the reason the futex
|
|
// is about to wake up.
|
|
FutexState state_;
|
|
|
|
// Shared futex lock for all runtimes. We can perhaps do better,
|
|
// but any lock will need to be per-domain (consider SharedWorker)
|
|
// or coarser.
|
|
static mozilla::Atomic<js::Mutex*> lock_;
|
|
|
|
// A flag that controls whether waiting is allowed.
|
|
bool canWait_;
|
|
};
|
|
|
|
JSObject*
|
|
InitAtomicsClass(JSContext* cx, HandleObject obj);
|
|
|
|
} /* namespace js */
|
|
|
|
#endif /* builtin_AtomicsObject_h */
|