prex
Version:
Async coordination primitives and extensions on top of ES6 Promises
107 lines (105 loc) • 3.82 kB
JavaScript
;
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Licensed under the Apache License, Version 2.0.
See LICENSE file in the project root for details.
***************************************************************************** */
Object.defineProperty(exports, "__esModule", { value: true });
const list_1 = require("./list");
const cancellation_1 = require("./cancellation");
const utils_1 = require("./utils");
const adapter_1 = require("./adapter");
const MAX_INT32 = -1 >>> 1;
/**
* Limits the number of asynchronous operations that can access a resource
* or pool of resources.
*/
class Semaphore {
/**
* Initializes a new instance of the Semaphore class.
*
* @param initialCount The initial number of entries.
* @param maxCount The maximum number of entries.
*/
constructor(initialCount, maxCount) {
this._waiters = new list_1.LinkedList();
if (utils_1.isMissing(maxCount))
maxCount = MAX_INT32;
if (!utils_1.isNumber(initialCount))
throw new TypeError("Number expected: initialCount.");
if (!utils_1.isNumber(maxCount))
throw new TypeError("Number expected: maxCount.");
if ((initialCount |= 0) < 0)
throw new RangeError("Argument out of range: initialCount.");
if ((maxCount |= 0) < 1)
throw new RangeError("Argument out of range: maxCount.");
if (initialCount > maxCount)
throw new RangeError("Argument out of range: initialCount.");
this._currentCount = initialCount;
this._maxCount = maxCount;
}
/**
* Gets the number of remaining asynchronous operations that can enter
* the Semaphore.
*/
get count() {
return this._currentCount;
}
/**
* Asynchronously waits for the event to become signaled.
*
* @param token A CancellationToken used to cancel the request.
*/
wait(token) {
return new Promise((resolve, reject) => {
const _token = adapter_1.getToken(token);
_token.throwIfCancellationRequested();
if (this._currentCount > 0) {
this._currentCount--;
resolve();
return;
}
const node = this._waiters.push(() => {
registration.unregister();
if (_token.cancellationRequested) {
reject(new cancellation_1.CancelError());
}
else {
resolve();
}
});
const registration = _token.register(() => {
if (node.list) {
node.list.deleteNode(node);
reject(new cancellation_1.CancelError());
}
});
});
}
/**
* Releases the Semaphore one or more times.
*
* @param count The number of times to release the Semaphore.
*/
release(count) {
if (utils_1.isMissing(count))
count = 1;
if (!utils_1.isNumber(count))
throw new TypeError("Number expected: count.");
if ((count |= 0) < 1)
throw new RangeError("Argument out of range: count.");
if (this._maxCount - this._currentCount < count)
throw new RangeError("Argument out of range: count.");
while (count > 0) {
count--;
const resolve = this._waiters.shift();
if (resolve) {
resolve();
}
else {
this._currentCount++;
}
}
}
}
exports.Semaphore = Semaphore;