summaryrefslogtreecommitdiff
path: root/core/shared_queue.js
diff options
context:
space:
mode:
Diffstat (limited to 'core/shared_queue.js')
-rw-r--r--core/shared_queue.js205
1 files changed, 205 insertions, 0 deletions
diff --git a/core/shared_queue.js b/core/shared_queue.js
new file mode 100644
index 000000000..7eeb61255
--- /dev/null
+++ b/core/shared_queue.js
@@ -0,0 +1,205 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+/*
+SharedQueue Binary Layout
++-------------------------------+-------------------------------+
+| NUM_RECORDS (32) |
++---------------------------------------------------------------+
+| NUM_SHIFTED_OFF (32) |
++---------------------------------------------------------------+
+| HEAD (32) |
++---------------------------------------------------------------+
+| OFFSETS (32) |
++---------------------------------------------------------------+
+| RECORD_ENDS (*MAX_RECORDS) ...
++---------------------------------------------------------------+
+| RECORDS (*MAX_RECORDS) ...
++---------------------------------------------------------------+
+ */
+
+/* eslint-disable @typescript-eslint/no-use-before-define */
+
+(window => {
+ const GLOBAL_NAMESPACE = "Deno";
+ const CORE_NAMESPACE = "core";
+ const MAX_RECORDS = 100;
+ const INDEX_NUM_RECORDS = 0;
+ const INDEX_NUM_SHIFTED_OFF = 1;
+ const INDEX_HEAD = 2;
+ const INDEX_OFFSETS = 3;
+ const INDEX_RECORDS = INDEX_OFFSETS + 2 * MAX_RECORDS;
+ const HEAD_INIT = 4 * INDEX_RECORDS;
+
+ // Available on start due to bindings.
+ const Deno = window[GLOBAL_NAMESPACE];
+ const core = Deno[CORE_NAMESPACE];
+ // Warning: DO NOT use window.Deno after this point.
+ // It is possible that the Deno namespace has been deleted.
+ // Use the above local Deno and core variable instead.
+
+ let sharedBytes;
+ let shared32;
+ let initialized = false;
+
+ function maybeInit() {
+ if (!initialized) {
+ init();
+ initialized = true;
+ }
+ }
+
+ function init() {
+ const shared = Deno.core.shared;
+ assert(shared.byteLength > 0);
+ assert(sharedBytes == null);
+ assert(shared32 == null);
+ sharedBytes = new Uint8Array(shared);
+ shared32 = new Int32Array(shared);
+ // Callers should not call Deno.core.recv, use setAsyncHandler.
+ Deno.core.recv(handleAsyncMsgFromRust);
+ }
+
+ function ops() {
+ // op id 0 is a special value to retreive the map of registered ops.
+ const opsMapBytes = Deno.core.send(0, new Uint8Array([]), null);
+ const opsMapJson = String.fromCharCode.apply(null, opsMapBytes);
+ return JSON.parse(opsMapJson);
+ }
+
+ function assert(cond) {
+ if (!cond) {
+ throw Error("assert");
+ }
+ }
+
+ function reset() {
+ maybeInit();
+ shared32[INDEX_NUM_RECORDS] = 0;
+ shared32[INDEX_NUM_SHIFTED_OFF] = 0;
+ shared32[INDEX_HEAD] = HEAD_INIT;
+ }
+
+ function head() {
+ maybeInit();
+ return shared32[INDEX_HEAD];
+ }
+
+ function numRecords() {
+ return shared32[INDEX_NUM_RECORDS];
+ }
+
+ function size() {
+ return shared32[INDEX_NUM_RECORDS] - shared32[INDEX_NUM_SHIFTED_OFF];
+ }
+
+ function setMeta(index, end, opId) {
+ shared32[INDEX_OFFSETS + 2 * index] = end;
+ shared32[INDEX_OFFSETS + 2 * index + 1] = opId;
+ }
+
+ function getMeta(index) {
+ if (index < numRecords()) {
+ const buf = shared32[INDEX_OFFSETS + 2 * index];
+ const opId = shared32[INDEX_OFFSETS + 2 * index + 1];
+ return [opId, buf];
+ } else {
+ return null;
+ }
+ }
+
+ function getOffset(index) {
+ if (index < numRecords()) {
+ if (index == 0) {
+ return HEAD_INIT;
+ } else {
+ return shared32[INDEX_OFFSETS + 2 * (index - 1)];
+ }
+ } else {
+ return null;
+ }
+ }
+
+ function push(opId, buf) {
+ const off = head();
+ const end = off + buf.byteLength;
+ const index = numRecords();
+ if (end > shared32.byteLength || index >= MAX_RECORDS) {
+ // console.log("shared_queue.js push fail");
+ return false;
+ }
+ setMeta(index, end, opId);
+ assert(end - off == buf.byteLength);
+ sharedBytes.set(buf, off);
+ shared32[INDEX_NUM_RECORDS] += 1;
+ shared32[INDEX_HEAD] = end;
+ return true;
+ }
+
+ /// Returns null if empty.
+ function shift() {
+ const i = shared32[INDEX_NUM_SHIFTED_OFF];
+ if (size() == 0) {
+ assert(i == 0);
+ return null;
+ }
+
+ const off = getOffset(i);
+ const [opId, end] = getMeta(i);
+
+ if (size() > 1) {
+ shared32[INDEX_NUM_SHIFTED_OFF] += 1;
+ } else {
+ reset();
+ }
+
+ assert(off != null);
+ assert(end != null);
+ const buf = sharedBytes.subarray(off, end);
+ return [opId, buf];
+ }
+
+ let asyncHandler;
+ function setAsyncHandler(cb) {
+ maybeInit();
+ assert(asyncHandler == null);
+ asyncHandler = cb;
+ }
+
+ function handleAsyncMsgFromRust(opId, buf) {
+ if (buf) {
+ // This is the overflow_response case of deno::Isolate::poll().
+ asyncHandler(opId, buf);
+ } else {
+ while (true) {
+ const opIdBuf = shift();
+ if (opIdBuf == null) {
+ break;
+ }
+ asyncHandler(...opIdBuf);
+ }
+ }
+ }
+
+ function dispatch(opId, control, zeroCopy = null) {
+ maybeInit();
+ return Deno.core.send(opId, control, zeroCopy);
+ }
+
+ const denoCore = {
+ setAsyncHandler,
+ dispatch,
+ sharedQueue: {
+ MAX_RECORDS,
+ head,
+ numRecords,
+ size,
+ push,
+ reset,
+ shift
+ },
+ ops
+ };
+
+ assert(window[GLOBAL_NAMESPACE] != null);
+ assert(window[GLOBAL_NAMESPACE][CORE_NAMESPACE] != null);
+ Object.assign(core, denoCore);
+})(this);