mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 15:24:46 -05:00
141 lines
3.3 KiB
TypeScript
141 lines
3.3 KiB
TypeScript
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
const targetDir = Deno.execPath().replace(/[^\/\\]+$/, "");
|
|
const [libPrefix, libSuffix] = {
|
|
darwin: ["lib", "dylib"],
|
|
linux: ["lib", "so"],
|
|
windows: ["", "dll"],
|
|
}[Deno.build.os];
|
|
const libPath = `${targetDir}/${libPrefix}test_ffi.${libSuffix}`;
|
|
|
|
const dylib = Deno.dlopen(
|
|
libPath,
|
|
{
|
|
store_function_2: {
|
|
parameters: ["function"],
|
|
result: "void",
|
|
},
|
|
call_stored_function_2: {
|
|
parameters: ["u8"],
|
|
result: "void",
|
|
},
|
|
call_stored_function_2_from_other_thread: {
|
|
name: "call_stored_function_2",
|
|
parameters: ["u8"],
|
|
result: "void",
|
|
nonblocking: true,
|
|
},
|
|
call_stored_function_2_thread_safe: {
|
|
parameters: ["u8"],
|
|
result: "void",
|
|
},
|
|
} as const,
|
|
);
|
|
|
|
globalThis.addEventListener("error", (data) => {
|
|
console.log("Unhandled error");
|
|
data.preventDefault();
|
|
});
|
|
globalThis.onerror = (data) => {
|
|
console.log("Unhandled error");
|
|
if (typeof data !== "string") {
|
|
data.preventDefault();
|
|
}
|
|
};
|
|
|
|
globalThis.addEventListener("unhandledrejection", (data) => {
|
|
console.log("Unhandled rejection");
|
|
data.preventDefault();
|
|
});
|
|
|
|
const timer = setTimeout(() => {
|
|
console.error(
|
|
"Test failed, final callback did not get picked up by Deno event loop",
|
|
);
|
|
Deno.exit(-1);
|
|
}, 5_000);
|
|
|
|
Deno.unrefTimer(timer);
|
|
|
|
enum CallCase {
|
|
SyncSelf,
|
|
SyncFfi,
|
|
AsyncSelf,
|
|
AsyncSyncFfi,
|
|
AsyncFfi,
|
|
}
|
|
type U8CallCase = Deno.NativeU8Enum<CallCase>;
|
|
|
|
const throwCb = (c: CallCase): number => {
|
|
console.log("CallCase:", CallCase[c]);
|
|
if (c === CallCase.AsyncFfi) {
|
|
cb.unref();
|
|
}
|
|
throw new Error("Error");
|
|
};
|
|
|
|
const THROW_CB_DEFINITION = {
|
|
parameters: ["u8" as U8CallCase],
|
|
result: "u8",
|
|
} as const;
|
|
|
|
const cb = new Deno.UnsafeCallback(THROW_CB_DEFINITION, throwCb);
|
|
|
|
try {
|
|
const fnPointer = new Deno.UnsafeFnPointer(cb.pointer, THROW_CB_DEFINITION);
|
|
|
|
fnPointer.call(CallCase.SyncSelf);
|
|
} catch (_err) {
|
|
console.log(
|
|
"Throwing errors from an UnsafeCallback called from a synchronous UnsafeFnPointer works. Terribly excellent.",
|
|
);
|
|
}
|
|
|
|
dylib.symbols.store_function_2(cb.pointer);
|
|
try {
|
|
dylib.symbols.call_stored_function_2(CallCase.SyncFfi);
|
|
} catch (_err) {
|
|
console.log(
|
|
"Throwing errors from an UnsafeCallback called from a synchronous FFI symbol works. Terribly excellent.",
|
|
);
|
|
}
|
|
|
|
try {
|
|
const fnPointer = new Deno.UnsafeFnPointer(cb.pointer, {
|
|
...THROW_CB_DEFINITION,
|
|
nonblocking: true,
|
|
});
|
|
await fnPointer.call(CallCase.AsyncSelf);
|
|
} catch (err) {
|
|
throw new Error(
|
|
"Nonblocking UnsafeFnPointer should not be threading through a JS error thrown on the other side of the call",
|
|
{
|
|
cause: err,
|
|
},
|
|
);
|
|
}
|
|
|
|
try {
|
|
await dylib.symbols.call_stored_function_2_from_other_thread(
|
|
CallCase.AsyncSyncFfi,
|
|
);
|
|
} catch (err) {
|
|
throw new Error(
|
|
"Nonblocking symbol call should not be threading through a JS error thrown on the other side of the call",
|
|
{
|
|
cause: err,
|
|
},
|
|
);
|
|
}
|
|
try {
|
|
// Ref the callback to make sure we do not exit before the call is done.
|
|
cb.ref();
|
|
dylib.symbols.call_stored_function_2_thread_safe(CallCase.AsyncFfi);
|
|
} catch (err) {
|
|
throw new Error(
|
|
"Blocking symbol call should not be travelling 1.5 seconds forward in time to figure out that it call will trigger a JS error to be thrown",
|
|
{
|
|
cause: err,
|
|
},
|
|
);
|
|
}
|