blob: 5999dab7dcfe0fc1c7f86c99dd6bceb4b89f584d [file] [edit]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Shared locking structure suitable for synchronising syscalls
* between webworkers.
*/
/**
* Locking type that's more analagous to a Win32-style signal. This class
* creates locking semantics and a return code around a piece of shared memory
* supplied at construction time. This lets two threads share a communications
* channel, as one thread can lock() and wait() while another thread performs
* the unlock() when execution in the original thread should continue.
*/
export class SyscallLock {
/**
* Creates an instance of SyscallLock.
*
* @param {SharedArrayBuffer!} shared_buffer Shared memory for this lock.
*/
constructor(shared_buffer) {
this.UNLOCKED = 0;
this.LOCKED = 1;
// Must have space for 2 Int32 types in this shared memory buffer, the lock
// will live at |lockIndex| in the shared_buffer, the return code will live
// at |retcodeIndex|.
this.sabArr = new Int32Array(shared_buffer, 0, 2);
this.lockIndex = 0;
this.retcodeIndex = 1;
}
/**
* Sets |lockIndex| to LOCKED, the caller must *not* already hold the lock
* when making this call.
*
* @return {boolean} True if the lock was acquired, False otherwise.
*/
lock() {
// TODO(ajws@): Check if the lock is already held.
return this.UNLOCKED ===
Atomics.compareExchange(
this.sabArr, this.lockIndex, this.UNLOCKED, this.LOCKED);
}
/**
* Blocks execution of the caller while lockIndex remains in the LOCKED
* state.
*/
wait() {
Atomics.wait(this.sabArr, this.lockIndex, this.LOCKED);
}
/**
* Unlock lockIndex, this does not check to see if the lock is currenly held
* by anyone.
*/
unlock() {
Atomics.store(this.sabArr, this.lockIndex, this.UNLOCKED);
Atomics.notify(this.sabArr, this.lockIndex);
}
/**
* Set the return code for a syscall.
*
* @param {number} retcode Must be be able to fit into an Int32, should be one
* of the values of ./wasi/errno.js.
*/
setRetcode(retcode) {
Atomics.store(this.sabArr, this.retcodeIndex, retcode);
}
/**
* Get the returncode of the last syscall made using this lock.
*
* @return {number} A syscall result from ./wasi/errno.js.
*/
getRetcode() {
return Atomics.load(this.sabArr, this.retcodeIndex);
}
}