atomics-sync
Version:
JavaScript multithreading synchronization library
3 lines (2 loc) • 6.01 kB
JavaScript
class E extends Error{constructor(E){super(E),this.name="DeadlockError"}}class r extends Error{constructor(E){super(E),this.name="PermissionError"}}class t extends Error{constructor(E){super(E),this.name="InvalidError"}}const e=2147483647,a=-2147483648,{compareExchange:o,wait:n,notify:i,store:c,load:T}=Atomics;class s{static init(){const E=new Int32Array(new SharedArrayBuffer(2*Int32Array.BYTES_PER_ELEMENT));return c(E,s.INDEX_STATE,s.STATE_UNLOCKED),c(E,s.INDEX_OWNER,s.OWNER_EMPTY),E}static lock(E,r){for(s.checkThreadIdBeforeLock(E,r);;){if(o(E,s.INDEX_STATE,s.STATE_UNLOCKED,s.STATE_LOCKED)===s.STATE_UNLOCKED)return void c(E,s.INDEX_OWNER,r);n(E,s.INDEX_STATE,s.STATE_LOCKED)}}static timedLock(E,r,t){for(s.checkThreadIdBeforeLock(E,r);;){if(o(E,s.INDEX_STATE,s.STATE_UNLOCKED,s.STATE_LOCKED)===s.STATE_UNLOCKED)return c(E,s.INDEX_OWNER,r),!0;const e=t-Date.now();if("timed-out"===n(E,s.INDEX_STATE,s.STATE_LOCKED,e))return!1}}static tryLock(E,r){return s.checkThreadIdBeforeLock(E,r),o(E,s.INDEX_STATE,s.STATE_UNLOCKED,s.STATE_LOCKED)===s.STATE_UNLOCKED&&(c(E,s.INDEX_OWNER,r),!0)}static unlock(E,t){if(s.checkThreadIdIsValid(t),T(E,s.INDEX_OWNER)!==t)throw new r("current thread is not owner of mutex");if(c(E,s.INDEX_OWNER,s.OWNER_EMPTY),o(E,s.INDEX_STATE,s.STATE_LOCKED,s.STATE_UNLOCKED)===s.STATE_UNLOCKED)throw new r("mutex was not locked");i(E,s.INDEX_STATE,1)}static checkThreadIdBeforeLock(r,t){if(s.checkThreadIdIsValid(t),T(r,s.INDEX_OWNER)===t)throw new E("thread already owns this mutex")}static checkThreadIdIsValid(E){if(!Number.isInteger(E))throw new t("threadId should be int32");if(E<a||E>e)throw new RangeError("threadId is out of int32 range");if(E===s.OWNER_EMPTY)throw new t("threadId is empty owner")}}s.OWNER_EMPTY=0,s.STATE_UNLOCKED=0,s.STATE_LOCKED=1,s.INDEX_STATE=0,s.INDEX_OWNER=1;const{compareExchange:N,wait:_,notify:I,store:D,load:d}=Atomics;class A{static init(E){if(!Number.isInteger(E))throw new t("initial value should be int32");if(E<0||E>e)throw new RangeError("initial value should be greater or equal zero and less or equal maximum int32 value");const r=new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));return D(r,A.INDEX_VALUE,E),r}static wait(E){for(;;){const r=d(E,A.INDEX_VALUE);if(r>0){if(N(E,A.INDEX_VALUE,r,r-1)===r)return}else _(E,A.INDEX_VALUE,r)}}static timedWait(E,r){for(;;){const t=d(E,A.INDEX_VALUE);if(t>0){if(N(E,A.INDEX_VALUE,t,t-1)===t)return!0}else{const e=r-Date.now();if("timed-out"===_(E,A.INDEX_VALUE,t,e))return!1}}}static tryWait(E){for(;;){const r=d(E,A.INDEX_VALUE);if(0===r)return!1;if(N(E,A.INDEX_VALUE,r,r-1)===r)return!0}}static post(E){for(;;){const r=d(E,A.INDEX_VALUE);if(r===e)throw new RangeError("maximum limit reached for semaphore value");if(N(E,A.INDEX_VALUE,r,r+1)===r)return void(0===r&&I(E,A.INDEX_VALUE,1))}}static getValue(E){return d(E,A.INDEX_VALUE)}}A.INDEX_VALUE=0;const{wait:u,notify:h}=Atomics;class X{static init(){return new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT))}static signal(E){h(E,0,1)}static broadcast(E){h(E,0)}static wait(E,r,t){s.unlock(r,t),u(E,0,0),s.lock(r,t)}static timedWait(E,r,t,e){try{return s.unlock(r,t),"timed-out"!==u(E,0,0,e-Date.now())}finally{s.lock(r,t)}}}const{store:f,load:l,add:w}=Atomics;class O{static init(E){O.validateCount(E);const r=new BigInt64Array(new SharedArrayBuffer(3*BigInt64Array.BYTES_PER_ELEMENT));f(r,O.INDEX_COUNT,BigInt(E)),f(r,O.INDEX_WAITED,0n),f(r,O.INDEX_GENERATION,0n);return{barrier:r,mutex:s.init(),cond:X.init()}}static wait(E,r){s.lock(E.mutex,r);const t=l(E.barrier,O.INDEX_GENERATION),e=l(E.barrier,O.INDEX_COUNT),a=w(E.barrier,O.INDEX_WAITED,1n)+1n;try{if(a>=e)return f(E.barrier,O.INDEX_WAITED,0n),w(E.barrier,O.INDEX_GENERATION,1n),X.broadcast(E.cond),!0;for(;l(E.barrier,O.INDEX_GENERATION)===t;)X.wait(E.cond,E.mutex,r);return!1}finally{s.unlock(E.mutex,r)}}static validateCount(E){if(!Number.isInteger(E))throw new t("count should be integer");if(E<=0)throw new RangeError("count should be greater zero")}}O.INDEX_COUNT=0,O.INDEX_WAITED=1,O.INDEX_GENERATION=2;const{compareExchange:L,store:S,load:U}=Atomics;class C{static init(){const E=new Int32Array(new SharedArrayBuffer(2*Int32Array.BYTES_PER_ELEMENT));return S(E,C.INDEX_STATE,C.STATE_UNLOCKED),S(E,C.INDEX_OWNER,C.OWNER_EMPTY),E}static lock(E,r){for(C.checkThreadIdBeforeLock(E,r);;){if(L(E,C.INDEX_STATE,C.STATE_UNLOCKED,C.STATE_LOCKED)===C.STATE_UNLOCKED)return void S(E,C.INDEX_OWNER,r);"function"==typeof Atomics.pause&&Atomics.pause()}}static tryLock(E,r){return C.checkThreadIdBeforeLock(E,r),L(E,C.INDEX_STATE,C.STATE_UNLOCKED,C.STATE_LOCKED)===C.STATE_UNLOCKED&&(S(E,C.INDEX_OWNER,r),!0)}static unlock(E,t){if(C.checkThreadIdIsValid(t),U(E,C.INDEX_OWNER)!==t)throw new r("current thread is not owner of lock");if(S(E,C.INDEX_OWNER,C.OWNER_EMPTY),L(E,C.INDEX_STATE,C.STATE_LOCKED,C.STATE_UNLOCKED)===C.STATE_UNLOCKED)throw new r("lock was not locked")}static checkThreadIdBeforeLock(r,t){if(C.checkThreadIdIsValid(t),U(r,C.INDEX_OWNER)===t)throw new E("thread already owns this lock")}static checkThreadIdIsValid(E){if(!Number.isInteger(E))throw new t("threadId should be int32");if(E<a||E>e)throw new RangeError("threadId is out of int32 range");if(E===C.OWNER_EMPTY)throw new t("threadId is empty owner")}}C.OWNER_EMPTY=0,C.STATE_UNLOCKED=0,C.STATE_LOCKED=1,C.INDEX_STATE=0,C.INDEX_OWNER=1;const{compareExchange:m,store:k}=Atomics;class R{static init(){const E=new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));return k(E,R.INDEX_EXECUTED,R.EXECUTED_NO),E}static execute(E,r){m(E,R.INDEX_EXECUTED,R.EXECUTED_NO,R.EXECUTED_YES)===R.EXECUTED_NO&&r()}static isExecuted(E){return Atomics.load(E,R.INDEX_EXECUTED)===R.EXECUTED_YES}}R.INDEX_EXECUTED=0,R.EXECUTED_NO=0,R.EXECUTED_YES=1;export{O as Barrier,X as Condition,E as DeadlockError,e as INT32_MAX_VALUE,a as INT32_MIN_VALUE,t as InvalidError,s as Mutex,R as Once,r as PermissionError,A as Semaphore,C as SpinLock};
//# sourceMappingURL=atomics-sync.esm.min.js.map