Added support to wasm and custom runtimes

Use `ArsdUseCustomRuntime` for supporting them.
This commit is contained in:
Marcelo Silva Nascimento Mancini 2023-11-13 11:59:01 -03:00 committed by GitHub
parent 8cb756ba6f
commit 9f59feeca4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 57 additions and 31 deletions

88
core.d
View File

@ -32,11 +32,30 @@ module arsd.core;
// see: https://wiki.openssl.org/index.php/Simple_TLS_Server // see: https://wiki.openssl.org/index.php/Simple_TLS_Server
import core.thread; ///ArsdUseCustomRuntime is used since other derived work from WebAssembly may be used and thus specified in the CLI
import core.volatile; version(WebAssembly) version = ArsdUseCustomRuntime;
import core.atomic; version(ArsdUseCustomRuntime)
import core.time; {
version = EmptyEventLoop;
version = UseStdioWriteln;
}
else
{
version = HasFile;
version = HasSocket;
version = HasThread;
version = HasErrno;
}
version(HasThread)
{
import core.thread;
import core.volatile;
import core.atomic;
import core.time;
}
version(HasErrno)
import core.stdc.errno; import core.stdc.errno;
import core.attribute; import core.attribute;
@ -2083,7 +2102,7 @@ package(arsd) enum EventLoopType {
// the GC may not be able to see this! remember, it can be hidden inside kernel buffers // the GC may not be able to see this! remember, it can be hidden inside kernel buffers
private class CallbackHelper { version(HasThread) private class CallbackHelper {
import core.memory; import core.memory;
void call() { void call() {
@ -2307,7 +2326,7 @@ version(Windows) {
/++ /++
An `AbstractFile` represents a file handle on the operating system level. You cannot do much with it. An `AbstractFile` represents a file handle on the operating system level. You cannot do much with it.
+/ +/
class AbstractFile { version(HasFile) class AbstractFile {
private { private {
NativeFileHandle handle; NativeFileHandle handle;
} }
@ -2514,7 +2533,7 @@ class AbstractFile {
/++ /++
+/ +/
class File : AbstractFile { version(HasFile) class File : AbstractFile {
/++ /++
Opens a file in synchronous access mode. Opens a file in synchronous access mode.
@ -2553,7 +2572,7 @@ class File : AbstractFile {
/++ /++
Only one operation can be pending at any time in the current implementation. Only one operation can be pending at any time in the current implementation.
+/ +/
class AsyncFile : AbstractFile { version(HasFile) class AsyncFile : AbstractFile {
/++ /++
Opens a file in asynchronous access mode. Opens a file in asynchronous access mode.
+/ +/
@ -2855,7 +2874,7 @@ enum OnOutOfSpace {
interface lookup for bind (stream or dgram) interface lookup for bind (stream or dgram)
+/ +/
struct SocketAddress { version(HasSocket) struct SocketAddress {
import core.sys.posix.netdb; import core.sys.posix.netdb;
/++ /++
@ -3098,7 +3117,7 @@ private version(Windows) {
} }
} }
class AsyncSocket : AsyncFile { version(HasFile) class AsyncSocket : AsyncFile {
// otherwise: accept, bind, connect, shutdown, close. // otherwise: accept, bind, connect, shutdown, close.
static auto lastError() { static auto lastError() {
@ -3297,7 +3316,7 @@ class AsyncSocket : AsyncFile {
NOT IMPLEMENTED / NOT STABLE NOT IMPLEMENTED / NOT STABLE
+/ +/
class AsyncConnectRequest : AsyncOperationRequest { version(HasSocket) class AsyncConnectRequest : AsyncOperationRequest {
// FIXME: i should take a list of addresses and take the first one that succeeds, so a getaddrinfo can be sent straight in. // FIXME: i should take a list of addresses and take the first one that succeeds, so a getaddrinfo can be sent straight in.
this(AsyncSocket socket, SocketAddress address, ubyte[] dataToWrite) { this(AsyncSocket socket, SocketAddress address, ubyte[] dataToWrite) {
@ -3310,7 +3329,7 @@ class AsyncConnectRequest : AsyncOperationRequest {
} }
/++ /++
+/ +/
class AsyncConnectResponse : AsyncOperationResponse { version(HasSocket) class AsyncConnectResponse : AsyncOperationResponse {
const SystemErrorCode errorCode; const SystemErrorCode errorCode;
this(SystemErrorCode errorCode) { this(SystemErrorCode errorCode) {
@ -3330,7 +3349,7 @@ class AsyncConnectResponse : AsyncOperationResponse {
NOT IMPLEMENTED / NOT STABLE NOT IMPLEMENTED / NOT STABLE
+/ +/
class AsyncAcceptRequest : AsyncOperationRequest { version(HasSocket) class AsyncAcceptRequest : AsyncOperationRequest {
AsyncSocket socket; AsyncSocket socket;
override void start() {} override void start() {}
@ -3387,7 +3406,7 @@ class AsyncAcceptRequest : AsyncOperationRequest {
} }
/++ /++
+/ +/
class AsyncAcceptResponse : AsyncOperationResponse { version(HasSocket) class AsyncAcceptResponse : AsyncOperationResponse {
AsyncSocket newSocket; AsyncSocket newSocket;
const SystemErrorCode errorCode; const SystemErrorCode errorCode;
@ -3407,7 +3426,7 @@ class AsyncAcceptResponse : AsyncOperationResponse {
/++ /++
+/ +/
class AsyncReceiveRequest : AsyncOperationRequest { version(HasSocket) class AsyncReceiveRequest : AsyncOperationRequest {
struct LowLevelOperation { struct LowLevelOperation {
AsyncSocket file; AsyncSocket file;
ubyte[] buffer; ubyte[] buffer;
@ -3455,7 +3474,7 @@ class AsyncReceiveRequest : AsyncOperationRequest {
} }
/++ /++
+/ +/
class AsyncReceiveResponse : AsyncOperationResponse { version(HasSocket) class AsyncReceiveResponse : AsyncOperationResponse {
const ubyte[] bufferWritten; const ubyte[] bufferWritten;
const SystemErrorCode errorCode; const SystemErrorCode errorCode;
@ -3471,7 +3490,7 @@ class AsyncReceiveResponse : AsyncOperationResponse {
/++ /++
+/ +/
class AsyncSendRequest : AsyncOperationRequest { version(HasSocket) class AsyncSendRequest : AsyncOperationRequest {
struct LowLevelOperation { struct LowLevelOperation {
AsyncSocket file; AsyncSocket file;
const(ubyte)[] buffer; const(ubyte)[] buffer;
@ -3517,7 +3536,7 @@ class AsyncSendRequest : AsyncOperationRequest {
/++ /++
+/ +/
class AsyncSendResponse : AsyncOperationResponse { version(HasSocket) class AsyncSendResponse : AsyncOperationResponse {
const ubyte[] bufferWritten; const ubyte[] bufferWritten;
const SystemErrorCode errorCode; const SystemErrorCode errorCode;
@ -3539,7 +3558,7 @@ class AsyncSendResponse : AsyncOperationResponse {
NOT IMPLEMENTED / NOT STABLE NOT IMPLEMENTED / NOT STABLE
+/ +/
class StreamServer { version(HasSocket) class StreamServer {
AsyncSocket[] sockets; AsyncSocket[] sockets;
this(SocketAddress[] listenTo, int backlog = 8) { this(SocketAddress[] listenTo, int backlog = 8) {
@ -3586,7 +3605,7 @@ unittest {
NOT IMPLEMENTED / NOT STABLE NOT IMPLEMENTED / NOT STABLE
+/ +/
class DatagramListener { version(HasSocket) class DatagramListener {
// whenever a udp message arrives, it calls your callback // whenever a udp message arrives, it calls your callback
// can be on a specific thread or on any thread // can be on a specific thread or on any thread
@ -3597,7 +3616,7 @@ class DatagramListener {
/++ /++
Just in case I decide to change the implementation some day. Just in case I decide to change the implementation some day.
+/ +/
alias AsyncAnonymousPipe = AsyncFile; version(HasFile) alias AsyncAnonymousPipe = AsyncFile;
// AsyncAnonymousPipe connectNamedPipe(AsyncAnonymousPipe preallocated, string name) // AsyncAnonymousPipe connectNamedPipe(AsyncAnonymousPipe preallocated, string name)
@ -3614,7 +3633,7 @@ alias AsyncAnonymousPipe = AsyncFile;
History: History:
previously in minigui as a private function. Moved to arsd.core on April 3, 2023 previously in minigui as a private function. Moved to arsd.core on April 3, 2023
+/ +/
GetFilesResult getFiles(string directory, scope void delegate(string name, bool isDirectory) dg) { version(HasFile) GetFilesResult getFiles(string directory, scope void delegate(string name, bool isDirectory) dg) {
// FIXME: my buffers here aren't great lol // FIXME: my buffers here aren't great lol
SavedArgument[1] argsForException() { SavedArgument[1] argsForException() {
@ -4220,7 +4239,7 @@ mixin template OverlappedIoRequest(Response, LowLevelOperation) {
/++ /++
You can write to a file asynchronously by creating one of these. You can write to a file asynchronously by creating one of these.
+/ +/
final class AsyncWriteRequest : AsyncOperationRequest { version(HasSocket) final class AsyncWriteRequest : AsyncOperationRequest {
struct LowLevelOperation { struct LowLevelOperation {
AsyncFile file; AsyncFile file;
ubyte[] buffer; ubyte[] buffer;
@ -4274,7 +4293,7 @@ class AsyncWriteResponse : AsyncOperationResponse {
/++ /++
+/ +/
final class AsyncReadRequest : AsyncOperationRequest { version(HasSocket) final class AsyncReadRequest : AsyncOperationRequest {
struct LowLevelOperation { struct LowLevelOperation {
AsyncFile file; AsyncFile file;
ubyte[] buffer; ubyte[] buffer;
@ -4344,7 +4363,7 @@ class AsyncReadResponse : AsyncOperationResponse {
runHelperFunction() - whomever it reports to is the parent runHelperFunction() - whomever it reports to is the parent
+/ +/
class ScheduableTask : Fiber { version(HasThread) class ScheduableTask : Fiber {
private void delegate() dg; private void delegate() dg;
// linked list stuff // linked list stuff
@ -4435,7 +4454,7 @@ void delegate(Throwable t) taskUncaughtException;
History: History:
Added August 11, 2023 (dub v11.1) Added August 11, 2023 (dub v11.1)
+/ +/
SchedulableTaskController inSchedulableTask() { version(HasThread) SchedulableTaskController inSchedulableTask() {
import core.thread.fiber; import core.thread.fiber;
if(auto fiber = Fiber.getThis) { if(auto fiber = Fiber.getThis) {
@ -4446,7 +4465,7 @@ SchedulableTaskController inSchedulableTask() {
} }
/// ditto /// ditto
struct SchedulableTaskController { version(HasThread) struct SchedulableTaskController {
private this(ScheduableTask fiber) { private this(ScheduableTask fiber) {
this.fiber = fiber; this.fiber = fiber;
} }
@ -4497,7 +4516,7 @@ class TaskCancelledException : object.Exception {
} }
} }
private class CoreWorkerThread : Thread { version(HasThread) private class CoreWorkerThread : Thread {
this(EventLoopType type) { this(EventLoopType type) {
this.type = type; this.type = type;
@ -4596,7 +4615,7 @@ private int numberOfCpus() {
Its destructor runs the event loop then waits to for the workers to finish to clean them up. Its destructor runs the event loop then waits to for the workers to finish to clean them up.
+/ +/
// FIXME: single instance? // FIXME: single instance?
struct ArsdCoreApplication { version(HasThread) struct ArsdCoreApplication {
private ICoreEventLoop impl; private ICoreEventLoop impl;
/++ /++
@ -4650,6 +4669,7 @@ struct ArsdCoreApplication {
private class CoreEventLoopImplementation : ICoreEventLoop { private class CoreEventLoopImplementation : ICoreEventLoop {
version(EmptyEventLoop) void runOnce(){}
version(Arsd_core_kqueue) { version(Arsd_core_kqueue) {
// this thread apc dispatches go as a custom event to the queue // this thread apc dispatches go as a custom event to the queue
@ -5579,7 +5599,7 @@ class WritableStream {
It reads binary data. It reads binary data.
+/ +/
class ReadableStream { version(HasThread) class ReadableStream {
this() { this() {
@ -6259,7 +6279,13 @@ void writeln(T...)(T t) {
} }
private void actuallyWriteToStdout(scope char[] buffer) @trusted { private void actuallyWriteToStdout(scope char[] buffer) @trusted {
version(Windows) {
version(UseStdioWriteln)
{
import std.stdio;
writeln(buffer);
}
else version(Windows) {
import core.sys.windows.wincon; import core.sys.windows.wincon;
auto hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); auto hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);