diff --git a/core/http/TODO.md b/core/http/TODO.md index 47c9dd87782..77241e8d4fb 100644 --- a/core/http/TODO.md +++ b/core/http/TODO.md @@ -66,11 +66,14 @@ - [ ] Windows - [ ] check if some of the calls need to take a flags bitset. - [ ] don't use os.Errno or os package at all -- [ ] consider making the `IO` a thread local global + - [x] Darwin + - [ ] Linux + - [ ] Windows +- [x] consider making the `IO` a thread local global - [ ] calm down the cpu use - [x] Linux - [x] Darwin - - [ ] Windows + - [?] Windows - [ ] A way to tick without blocking # Non critical wants diff --git a/core/nbio/nbio.odin b/core/nbio/api.odin similarity index 97% rename from core/nbio/nbio.odin rename to core/nbio/api.odin index 137bbf7e05f..6fe8747c60a 100644 --- a/core/nbio/nbio.odin +++ b/core/nbio/api.odin @@ -1,6 +1,5 @@ package nbio -import "core:os" import "core:time" /* @@ -15,12 +14,12 @@ Inputs: Returns: - err: An error code when something went when retrieving events, 0 otherwise */ -tick :: proc() -> os.Errno { +tick :: proc() -> General_Error { if !g_io.initialized { return nil } return _tick(&g_io) } -run :: proc() -> os.Errno { +run :: proc() -> General_Error { if !g_io.initialized { return nil } for _num_waiting(&g_io) > 0 { if errno := _tick(&g_io); errno != nil { @@ -98,6 +97,8 @@ with_timeout :: proc(io: ^IO, dur: time.Duration, target: ^Completion, loc := #c return _timeout_completion(io, dur, target) } +Handle :: _Handle + // TODO: should this be configurable, with a minimum of course for the use of core? MAX_USER_ARGUMENTS :: size_of(rawptr) * 5 diff --git a/core/nbio/nbio_other.odin b/core/nbio/api_os.odin similarity index 81% rename from core/nbio/nbio_other.odin rename to core/nbio/api_os.odin index 65b3b1146fd..2b13a4b7081 100644 --- a/core/nbio/nbio_other.odin +++ b/core/nbio/api_os.odin @@ -1,7 +1,6 @@ #+build !js package nbio -import "core:os" import "core:net" /* @@ -64,10 +63,22 @@ Inputs: Returns: - err: A network error that happened when starting listening */ -listen :: proc(socket: net.TCP_Socket, backlog := 1000) -> (err: net.Network_Error) { +listen :: proc(socket: net.TCP_Socket, backlog := 1000) -> (err: net.Listen_Error) { return _listen(socket, backlog) } +File_Flags :: distinct bit_set[File_Flag; int] +File_Flag :: enum { + Read, + Write, + Append, + Create, + Excl, + Sync, + Trunc, + Inheritable, +} + /* Opens a file hande, sets non blocking mode and relates it to the given IO @@ -83,7 +94,7 @@ Returns: - handle: The file handle - err: The error code when an error occured, 0 otherwise */ -open :: proc(path: string, mode: int = os.O_RDONLY, perm: int = 0) -> (handle: os.Handle, err: os.Errno) { +open :: proc(path: string, mode: File_Flags = {.Read}, perm: int = 0o777) -> (handle: Handle, err: FS_Error) { return _open(io(), path, mode, perm) } @@ -94,7 +105,7 @@ Returns: - size: The size of the file in bytes - err: The error when an error occured, 0 otherwise */ -file_size :: proc(fd: os.Handle) -> (size: i64, err: os.Errno) { +file_size :: proc(fd: Handle) -> (size: i64, err: FS_Error) { return _file_size(io(), fd) } @@ -105,13 +116,13 @@ Closable :: union #no_nil { net.TCP_Socket, net.UDP_Socket, net.Socket, - os.Handle, + Handle, } -On_Close :: #type proc(user: rawptr, ok: bool) +On_Close :: #type proc(user: rawptr, err: FS_Error) @private -empty_on_close :: proc(_: rawptr, _: bool) {} +empty_on_close :: proc(_: rawptr, _: FS_Error) {} /* Closes the given `Closable` socket or file handle that was originally created by this package. @@ -126,7 +137,7 @@ close :: proc(fd: Closable, user: rawptr = nil, callback: On_Close = empty_on_cl return _close(io(), fd, user, callback) } -On_Accept :: #type proc(user: rawptr, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) +On_Accept :: #type proc(user: rawptr, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) /* Using the given socket, accepts the next incoming connection, calling the callback when that happens @@ -163,7 +174,12 @@ connect :: proc(endpoint: net.Endpoint, user: rawptr, callback: On_Connect) -> ^ return completion } -On_Recv :: #type proc(user: rawptr, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error) +On_Recv_TCP :: #type proc(user: rawptr, received: int, err: net.TCP_Recv_Error) +On_Recv_UDP :: #type proc(user: rawptr, received: int, udp_client: net.Endpoint, err: net.UDP_Recv_Error) +On_Recv :: union { + On_Recv_TCP, + On_Recv_UDP, +} /* Receives from the given socket, at most `len(buf)` bytes, and calls the given callback @@ -175,7 +191,11 @@ Inputs: - socket: Either a `net.TCP_Socket` or a `net.UDP_Socket` (that was opened/returned by this package) to receive from - buf: The buffer to put received bytes into */ -recv :: proc(socket: net.Any_Socket, buf: []byte, user: rawptr, callback: On_Recv) -> ^Completion { +recv_tcp :: proc(socket: net.TCP_Socket, buf: []byte, user: rawptr, callback: On_Recv_TCP) -> ^Completion { + return _recv(io(), socket, buf, user, callback) +} + +recv_udp :: proc(socket: net.UDP_Socket, buf: []byte, user: rawptr, callback: On_Recv_UDP) -> ^Completion { return _recv(io(), socket, buf, user, callback) } @@ -189,11 +209,20 @@ Inputs: - socket: Either a `net.TCP_Socket` or a `net.UDP_Socket` (that was opened/returned by this package) to receive from - buf: The buffer to put received bytes into */ -recv_all :: proc(socket: net.Any_Socket, buf: []byte, user: rawptr, callback: On_Recv) -> ^Completion { +recv_all_tcp :: proc(socket: net.TCP_Socket, buf: []byte, user: rawptr, callback: On_Recv_TCP) -> ^Completion { + return _recv(io(), socket, buf, user, callback, all = true) +} + +recv_all_udp :: proc(socket: net.UDP_Socket, buf: []byte, user: rawptr, callback: On_Recv_UDP) -> ^Completion { return _recv(io(), socket, buf, user, callback, all = true) } -On_Sent :: #type proc(user: rawptr, sent: int, err: net.Network_Error) +On_Sent_TCP :: #type proc(user: rawptr, sent: int, err: net.TCP_Send_Error) +On_Sent_UDP :: #type proc(user: rawptr, sent: int, err: net.UDP_Send_Error) +On_Sent :: union { + On_Sent_TCP, + On_Sent_UDP, +} /* Sends at most `len(buf)` bytes from the given buffer over the socket connection, and calls the given callback @@ -205,7 +234,7 @@ Inputs: - socket: a `net.TCP_Socket` to send to - buf: The buffer send */ -send_tcp :: proc(socket: net.TCP_Socket, buf: []byte, user: rawptr, callback: On_Sent) -> ^Completion { +send_tcp :: proc(socket: net.TCP_Socket, buf: []byte, user: rawptr, callback: On_Sent_TCP) -> ^Completion { return _send(io(), socket, buf, user, callback) } @@ -225,7 +254,7 @@ send_udp :: proc( socket: net.UDP_Socket, buf: []byte, user: rawptr, - callback: On_Sent, + callback: On_Sent_UDP, ) -> ^Completion { return _send(io, socket, buf, user, callback, endpoint) } @@ -237,7 +266,7 @@ This will keep sending until either an error or the full buffer is sent NOTE: polymorphic variants for type safe user data are available under `send_all_tcp_poly`, `send_all_tcp_poly2`, and `send_all_tcp_poly3`. */ -send_all_tcp :: proc(socket: net.TCP_Socket, buf: []byte, user: rawptr, callback: On_Sent) -> ^Completion { +send_all_tcp :: proc(socket: net.TCP_Socket, buf: []byte, user: rawptr, callback: On_Sent_TCP) -> ^Completion { return _send(io(), socket, buf, user, callback, all = true) } @@ -254,12 +283,12 @@ send_all_udp :: proc( socket: net.UDP_Socket, buf: []byte, user: rawptr, - callback: On_Sent, + callback: On_Sent_UDP, ) -> ^Completion { return _send(io, socket, buf, user, callback, endpoint, all = true) } -On_Read :: #type proc(user: rawptr, read: int, err: os.Errno) +On_Read :: #type proc(user: rawptr, read: int, err: FS_Error) /* Reads from the given handle, at the given offset, at most `len(buf)` bytes, and calls the given callback @@ -272,7 +301,7 @@ Inputs: - offset: The offset to begin the read from - buf: The buffer to put read bytes into */ -read_at :: proc(fd: os.Handle, offset: int, buf: []byte, user: rawptr, callback: On_Read) -> ^Completion { +read_at :: proc(fd: Handle, offset: int, buf: []byte, user: rawptr, callback: On_Read) -> ^Completion { return _read(io(), fd, offset, buf, user, callback) } @@ -287,11 +316,11 @@ Inputs: - offset: The offset to begin the read from - buf: The buffer to put read bytes into */ -read_at_all :: proc(fd: os.Handle, offset: int, buf: []byte, user: rawptr, callback: On_Read) -> ^Completion { +read_at_all :: proc(fd: Handle, offset: int, buf: []byte, user: rawptr, callback: On_Read) -> ^Completion { return _read(io(), fd, offset, buf, user, callback, all = true) } -On_Write :: #type proc(user: rawptr, written: int, err: os.Errno) +On_Write :: #type proc(user: rawptr, written: int, err: FS_Error) /* Writes to the given handle, at the given offset, at most `len(buf)` bytes, and calls the given callback @@ -304,7 +333,7 @@ Inputs: - offset: The offset to begin the write from - buf: The buffer to write to the file */ -write_at :: proc(fd: os.Handle, offset: int, buf: []byte, user: rawptr, callback: On_Write) -> ^Completion { +write_at :: proc(fd: Handle, offset: int, buf: []byte, user: rawptr, callback: On_Write) -> ^Completion { return _write(io(), fd, offset, buf, user, callback) } @@ -321,10 +350,11 @@ Inputs: - offset: The offset to begin the write from - buf: The buffer to write to the file */ -write_at_all :: proc(fd: os.Handle, offset: int, buf: []byte, user: rawptr, callback: On_Write) -> ^Completion { +write_at_all :: proc(fd: Handle, offset: int, buf: []byte, user: rawptr, callback: On_Write) -> ^Completion { return _write(io(), fd, offset, buf, user, callback, true) } +// TODO: should this have an error too? On_Poll :: #type proc(user: rawptr, event: Poll_Event) /* @@ -338,7 +368,7 @@ Inputs: - event: Whether to call the callback when `fd` is ready to be read from, or be written to - multi: Keeps the poll after an event happens, calling the callback again for further events, remove poll with `remove` */ -poll :: proc(fd: os.Handle, event: Poll_Event, multi: bool, user: rawptr, callback: On_Poll) -> ^Completion { +poll :: proc(fd: Handle, event: Poll_Event, multi: bool, user: rawptr, callback: On_Poll) -> ^Completion { return _poll(io(), fd, event, multi, user, callback) } @@ -363,3 +393,4 @@ Operation :: union { Op_Poll, Op_Remove, } + diff --git a/core/nbio/poly.odin b/core/nbio/api_poly.odin similarity index 100% rename from core/nbio/poly.odin rename to core/nbio/api_poly.odin diff --git a/core/nbio/poly_other.odin b/core/nbio/api_poly_os.odin similarity index 55% rename from core/nbio/poly_other.odin rename to core/nbio/api_poly_os.odin index 9a47ae8c066..4cc469573e2 100644 --- a/core/nbio/poly_other.odin +++ b/core/nbio/api_poly_os.odin @@ -6,13 +6,13 @@ import "base:intrinsics" import "core:net" import "core:os" -close_poly :: proc(fd: Closable, p: $T, callback: $C/proc(p: T, ok: bool)) -> ^Completion +close_poly :: proc(fd: Closable, p: $T, callback: $C/proc(p: T, err: FS_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - completion := _close(io(), fd, nil, proc(completion: rawptr, ok: bool) { + completion := _close(io(), fd, nil, proc(completion: rawptr, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C)(rawptr(ptr))) p := unall((^T)(rawptr(ptr + size_of(C)))) - cb(p, ok) + cb(p, err) }) ptr := uintptr(&completion.user_args) @@ -24,14 +24,14 @@ close_poly :: proc(fd: Closable, p: $T, callback: $C/proc(p: T, ok: bool)) -> ^C return completion } -close_poly2 :: proc(fd: Closable, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, ok: bool)) -> ^Completion +close_poly2 :: proc(fd: Closable, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - completion := _close(io(), fd, nil, proc(completion: rawptr, ok: bool) { + completion := _close(io(), fd, nil, proc(completion: rawptr, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) - cb(p, p2, ok) + cb(p, p2, err) }) ptr := uintptr(&completion.user_args) @@ -44,15 +44,15 @@ close_poly2 :: proc(fd: Closable, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2 return completion } -close_poly3 :: proc(fd: Closable, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, ok: bool)) -> ^Completion +close_poly3 :: proc(fd: Closable, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - completion := _close(io(), fd, nil, proc(completion: rawptr, ok: bool) { + completion := _close(io(), fd, nil, proc(completion: rawptr, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) p3 := unall((^T3)(rawptr(ptr + size_of(C) + size_of(T) + size_of(T2)))) - cb(p, p2, p3, ok) + cb(p, p2, p3, err) }) ptr := uintptr(&completion.user_args) @@ -66,9 +66,9 @@ close_poly3 :: proc(fd: Closable, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: return completion } -accept_poly :: proc(socket: net.TCP_Socket, p: $T, callback: $C/proc(p: T, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error)) -> ^Completion +accept_poly :: proc(socket: net.TCP_Socket, p: $T, callback: $C/proc(p: T, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - completion := _accept(io(), socket, nil, proc(completion: rawptr, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + completion := _accept(io(), socket, nil, proc(completion: rawptr, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C)(rawptr(ptr))) p := unall((^T)(rawptr(ptr + size_of(C)))) @@ -84,9 +84,9 @@ accept_poly :: proc(socket: net.TCP_Socket, p: $T, callback: $C/proc(p: T, clien return completion } -accept_poly2 :: proc(socket: net.TCP_Socket, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error)) -> ^Completion +accept_poly2 :: proc(socket: net.TCP_Socket, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - completion := _accept(io(), socket, nil, proc(completion: rawptr, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + completion := _accept(io(), socket, nil, proc(completion: rawptr, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) @@ -104,9 +104,9 @@ accept_poly2 :: proc(socket: net.TCP_Socket, p: $T, p2: $T2, callback: $C/proc(p return completion } -accept_poly3 :: proc(socket: net.TCP_Socket, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error)) -> ^Completion +accept_poly3 :: proc(socket: net.TCP_Socket, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - completion := _accept(io(), socket, nil, proc(completion: rawptr, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + completion := _accept(io(), socket, nil, proc(completion: rawptr, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) @@ -198,14 +198,14 @@ connect_poly3 :: proc(endpoint: net.Endpoint, p: $T, p2: $T2, p3: $T3, callback: return completion } -_recv_poly :: proc(socket: net.Any_Socket, buf: []byte, all: bool, p: $T, callback: $C/proc(p: T, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +_recv_tcp_poly :: proc(socket: net.TCP_Socket, buf: []byte, all: bool, p: $T, callback: $C/proc(p: T, received: int, err: net.TCP_Recv_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - completion := _recv(io(), socket, buf, nil, proc(completion: rawptr, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error) { + completion := _recv(io(), socket, buf, nil, On_Recv_TCP(proc(completion: rawptr, received: int, err: net.TCP_Recv_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C)(rawptr(ptr))) p := unall((^T)(rawptr(ptr + size_of(C)))) - cb(p, received, udp_client, err) - }) + cb(p, received, err) + })) ptr := uintptr(&completion.user_args) @@ -216,15 +216,15 @@ _recv_poly :: proc(socket: net.Any_Socket, buf: []byte, all: bool, p: $T, callba return completion } -_recv_poly2 :: proc(socket: net.Any_Socket, buf: []byte, all: bool, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +_recv_tcp_poly2 :: proc(socket: net.TCP_Socket, buf: []byte, all: bool, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, err: net.TCP_Recv_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - completion := _recv(io(), socket, buf, nil, proc(completion: rawptr, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error) { + completion := _recv(io(), socket, buf, nil, On_Recv_TCP(proc(completion: rawptr, received: int, err: net.TCP_Recv_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) - cb(p, p2, received, udp_client, err) - }) + cb(p, p2, received, err) + })) ptr := uintptr(&completion.user_args) @@ -236,16 +236,76 @@ _recv_poly2 :: proc(socket: net.Any_Socket, buf: []byte, all: bool, p: $T, p2: $ return completion } -_recv_poly3 :: proc(socket: net.Any_Socket, buf: []byte, all: bool, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +_recv_tcp_poly3 :: proc(socket: net.TCP_Socket, buf: []byte, all: bool, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, err: net.TCP_Recv_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - completion := _recv(io(), socket, buf, nil, proc(completion: rawptr, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error) { + completion := _recv(io(), socket, buf, nil, On_Recv_TCP(proc(completion: rawptr, received: int, err: net.TCP_Recv_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) p3 := unall((^T3)(rawptr(ptr + size_of(C) + size_of(T) + size_of(T2)))) - cb(p, p2, p3, received, udp_client, err) - }) + cb(p, p2, p3, received, err) + })) + + ptr := uintptr(&completion.user_args) + + unals((^C) (rawptr(ptr)), callback) + unals((^T) (rawptr(ptr + size_of(callback))), p) + unals((^T2)(rawptr(ptr + size_of(callback) + size_of(p))), p2) + unals((^T3)(rawptr(ptr + size_of(callback) + size_of(p) + size_of(p2))), p3) + + completion.user_data = completion + return completion +} + +_recv_udp_poly :: proc(socket: net.UDP_Socket, buf: []byte, all: bool, p: $T, callback: $C/proc(p: T, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion + where size_of(T) <= MAX_USER_ARGUMENTS { + completion := _recv(io(), socket, buf, nil, On_Recv_UDP(proc(completion: rawptr, received: int, client: net.Endpoint, err: net.UDP_Recv_Error) { + ptr := uintptr(&((^Completion)(completion)).user_args) + cb := unall((^C)(rawptr(ptr))) + p := unall((^T)(rawptr(ptr + size_of(C)))) + cb(p, received, client, err) + })) + + ptr := uintptr(&completion.user_args) + + unals((^C)(rawptr(ptr)), callback) + unals((^T)(rawptr(ptr + size_of(callback))), p) + + completion.user_data = completion + return completion +} + +_recv_udp_poly2 :: proc(socket: net.UDP_Socket, buf: []byte, all: bool, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion + where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { + completion := _recv(io(), socket, buf, nil, On_Recv_UDP(proc(completion: rawptr, received: int, client: net.Endpoint, err: net.UDP_Recv_Error) { + ptr := uintptr(&((^Completion)(completion)).user_args) + cb := unall((^C) (rawptr(ptr))) + p := unall((^T) (rawptr(ptr + size_of(C)))) + p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) + cb(p, p2, received, client, err) + })) + + ptr := uintptr(&completion.user_args) + + unals((^C) (rawptr(ptr)), callback) + unals((^T) (rawptr(ptr + size_of(callback))), p) + unals((^T2)(rawptr(ptr + size_of(callback) + size_of(p))), p2) + + completion.user_data = completion + return completion +} + +_recv_udp_poly3 :: proc(socket: net.UDP_Socket, buf: []byte, all: bool, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion + where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { + completion := _recv(io(), socket, buf, nil, On_Recv_UDP(proc(completion: rawptr, received: int, client: net.Endpoint, err: net.UDP_Recv_Error) { + ptr := uintptr(&((^Completion)(completion)).user_args) + cb := unall((^C) (rawptr(ptr))) + p := unall((^T) (rawptr(ptr + size_of(C)))) + p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) + p3 := unall((^T3)(rawptr(ptr + size_of(C) + size_of(T) + size_of(T2)))) + cb(p, p2, p3, received, client, err) + })) ptr := uintptr(&completion.user_args) @@ -258,44 +318,134 @@ _recv_poly3 :: proc(socket: net.Any_Socket, buf: []byte, all: bool, p: $T, p2: $ return completion } -recv_poly :: #force_inline proc(socket: net.Any_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +recv_tcp_poly :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, received: int, err: net.TCP_Recv_Error)) -> ^Completion + where size_of(T) <= MAX_USER_ARGUMENTS { + return _recv_tcp_poly(socket, buf, false, p, callback) +} + +recv_tcp_poly2 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, err: net.TCP_Recv_Error)) -> ^Completion + where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { + return _recv_tcp_poly2(socket, buf, false, p, p2, callback) +} + +recv_tcp_poly3 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, err: net.TCP_Recv_Error)) -> ^Completion + where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { + return _recv_tcp_poly3(socket, buf, false, p, p2, p3, callback) +} + +recv_all_tcp_poly :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, received: int, err: net.TCP_Recv_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - return _recv_poly(socket, buf, false, p, callback) + return _recv_tcp_poly(socket, buf, true, p, callback) } -recv_poly2 :: #force_inline proc(socket: net.Any_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +recv_all_tcp_poly2 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, err: net.TCP_Recv_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - return _recv_poly2(socket, buf, false, p, p2, callback) + return _recv_tcp_poly2(socket, buf, true, p, p2, callback) } -recv_poly3 :: #force_inline proc(socket: net.Any_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +recv_all_tcp_poly3 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, err: net.TCP_Recv_Error)) -> ^Completion + where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { + return _recv_tcp_poly3(socket, buf, true, p, p2, p3, callback) +} + +recv_udp_poly :: #force_inline proc(socket: net.UDP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion + where size_of(T) <= MAX_USER_ARGUMENTS { + return _recv_udp_poly(socket, buf, false, p, callback) +} + +recv_udp_poly2 :: #force_inline proc(socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion + where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { + return _recv_udp_poly2(socket, buf, false, p, p2, callback) +} + +recv_udp_poly3 :: #force_inline proc(socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion + where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { + return _recv_udp_poly3(socket, buf, false, p, p2, p3, callback) +} + +recv_all_udp_poly :: #force_inline proc(socket: net.UDP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion + where size_of(T) <= MAX_USER_ARGUMENTS { + return _recv_udp_poly(socket, buf, true, p, callback) +} + +recv_all_udp_poly2 :: #force_inline proc(socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - return _recv_poly3(socket, buf, false, p, p2, p3, callback) + return _recv_udp_poly2(socket, buf, true, p, p2, callback) } -recv_all_poly :: #force_inline proc(socket: net.Any_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +recv_all_udp_poly3 :: #force_inline proc(socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, client: net.Endpoint, err: net.UDP_Recv_Error)) -> ^Completion + where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { + return _recv_udp_poly3(socket, buf, true, p, p2, p3, callback) +} + +_send_tcp_poly :: proc(socket: net.TCP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.TCP_Send_Error), all := false) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - return _recv_poly(socket, buf, true, p, callback) + completion := _send(io(), socket, buf, nil, On_Sent_TCP(proc(completion: rawptr, sent: int, err: net.TCP_Send_Error) { + ptr := uintptr(&((^Completion)(completion)).user_args) + cb := unall((^C)(rawptr(ptr))) + p := unall((^T)(rawptr(ptr + size_of(C)))) + cb(p, sent, err) + }), nil, all) + + ptr := uintptr(&completion.user_args) + + unals((^C)(rawptr(ptr)), callback) + unals((^T)(rawptr(ptr + size_of(callback))), p) + + completion.user_data = completion + return completion } -recv_all_poly2 :: #force_inline proc(socket: net.Any_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +_send_tcp_poly2 :: proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.TCP_Send_Error), all := false) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - return _recv_poly2(socket, buf, true, p, p2, callback) + completion := _send(io(), socket, buf, nil, On_Sent_TCP(proc(completion: rawptr, sent: int, err: net.TCP_Send_Error) { + ptr := uintptr(&((^Completion)(completion)).user_args) + cb := unall((^C) (rawptr(ptr))) + p := unall((^T) (rawptr(ptr + size_of(C)))) + p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) + cb(p, p2, sent, err) + }), nil, all) + + ptr := uintptr(&completion.user_args) + + unals((^C) (rawptr(ptr)), callback) + unals((^T) (rawptr(ptr + size_of(callback))), p) + unals((^T2)(rawptr(ptr + size_of(callback) + size_of(p))), p2) + + completion.user_data = completion + return completion } -recv_all_poly3 :: #force_inline proc(socket: net.Any_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error)) -> ^Completion +_send_tcp_poly3 :: proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.TCP_Send_Error), all := false) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - return _recv_poly3(socket, buf, true, p, p2, p3, callback) + completion := _send(io(), socket, buf, nil, On_Sent_TCP(proc(completion: rawptr, sent: int, err: net.TCP_Send_Error) { + ptr := uintptr(&((^Completion)(completion)).user_args) + cb := unall((^C) (rawptr(ptr))) + p := unall((^T) (rawptr(ptr + size_of(C)))) + p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) + p3 := unall((^T3)(rawptr(ptr + size_of(C) + size_of(T) + size_of(T2)))) + cb(p, p2, p3, sent, err) + }), nil, all) + + ptr := uintptr(&completion.user_args) + + unals((^C) (rawptr(ptr)), callback) + unals((^T) (rawptr(ptr + size_of(callback))), p) + unals((^T2)(rawptr(ptr + size_of(callback) + size_of(p))), p2) + unals((^T3)(rawptr(ptr + size_of(callback) + size_of(p) + size_of(p2))), p3) + + completion.user_data = completion + return completion } -_send_poly :: proc(socket: net.Any_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.Network_Error), endpoint: Maybe(net.Endpoint) = nil, all := false) -> ^Completion +_send_udp_poly :: proc(socket: net.UDP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.UDP_Send_Error), endpoint: net.Endpoint, all := false) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - completion := _send(io(), socket, buf, nil, proc(completion: rawptr, sent: int, err: net.Network_Error) { + completion := _send(io(), socket, buf, nil, On_Sent_UDP(proc(completion: rawptr, sent: int, err: net.UDP_Send_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C)(rawptr(ptr))) p := unall((^T)(rawptr(ptr + size_of(C)))) cb(p, sent, err) - }, endpoint, all) + }), endpoint, all) ptr := uintptr(&completion.user_args) @@ -306,15 +456,15 @@ _send_poly :: proc(socket: net.Any_Socket, buf: []byte, p: $T, callback: $C/proc return completion } -_send_poly2 :: proc(socket: net.Any_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.Network_Error), endpoint: Maybe(net.Endpoint) = nil, all := false) -> ^Completion +_send_udp_poly2 :: proc(socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.UDP_Send_Error), endpoint: net.Endpoint, all := false) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - completion := _send(io(), socket, buf, nil, proc(completion: rawptr, sent: int, err: net.Network_Error) { + completion := _send(io(), socket, buf, nil, On_Sent_UDP(proc(completion: rawptr, sent: int, err: net.UDP_Send_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) cb(p, p2, sent, err) - }, endpoint, all) + }), endpoint, all) ptr := uintptr(&completion.user_args) @@ -326,16 +476,16 @@ _send_poly2 :: proc(socket: net.Any_Socket, buf: []byte, p: $T, p2: $T2, callbac return completion } -_send_poly3 :: proc(socket: net.Any_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.Network_Error), endpoint: Maybe(net.Endpoint) = nil, all := false) -> ^Completion +_send_udp_poly3 :: proc(socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.UDP_Send_Error), endpoint: net.Endpoint, all := false) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - completion := _send(io(), socket, buf, nil, proc(completion: rawptr, sent: int, err: net.Network_Error) { + completion := _send(io(), socket, buf, nil, On_Sent_UDP(proc(completion: rawptr, sent: int, err: net.UDP_Send_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) p2 := unall((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) p3 := unall((^T3)(rawptr(ptr + size_of(C) + size_of(T) + size_of(T2)))) cb(p, p2, p3, sent, err) - }, endpoint, all) + }), endpoint, all) ptr := uintptr(&completion.user_args) @@ -348,71 +498,71 @@ _send_poly3 :: proc(socket: net.Any_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3 return completion } -send_tcp_poly :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.Network_Error)) -> ^Completion +send_tcp_poly :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.TCP_Send_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - return _send_poly(socket, buf, p, callback) + return _send_tcp_poly(socket, buf, p, callback) } -send_tcp_poly2 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.Network_Error)) -> ^Completion +send_tcp_poly2 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.TCP_Send_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - return _send_poly2(socket, buf, p, p2, callback) + return _send_tcp_poly2(socket, buf, p, p2, callback) } -send_tcp_poly3 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.Network_Error)) -> ^Completion +send_tcp_poly3 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.TCP_Send_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - return _send_poly3(socket, buf, p, p2, p3, callback) + return _send_tcp_poly3(socket, buf, p, p2, p3, callback) } -send_udp_poly :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.Network_Error)) -> ^Completion +send_udp_poly :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.UDP_Send_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - return _send_poly(socket, buf, p, callback, endpoint) + return _send_udp_poly(socket, buf, p, callback, endpoint) } -send_udp_poly2 :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.Network_Error)) -> ^Completion +send_udp_poly2 :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.UDP_Send_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - return _send_poly2(socket, buf, p, p2, callback, endpoint) + return _send_udp_poly2(socket, buf, p, p2, callback, endpoint) } -send_udp_poly3 :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.Network_Error)) -> ^Completion +send_udp_poly3 :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.UDP_Send_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - return _send_poly3(socket, buf, p, p2, p3, callback, endpoint) + return _send_udp_poly3(socket, buf, p, p2, p3, callback, endpoint) } -send_all_tcp_poly :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.Network_Error)) -> ^Completion +send_all_tcp_poly :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.TCP_Send_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - return _send_poly(socket, buf, p, callback, all = true) + return _send_tcp_poly(socket, buf, p, callback, all = true) } -send_all_tcp_poly2 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.Network_Error)) -> ^Completion +send_all_tcp_poly2 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.TCP_Send_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - return _send_poly2(socket, buf, p, p2, callback, all = true) + return _send_tcp_poly2(socket, buf, p, p2, callback, all = true) } -send_all_tcp_poly3 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.Network_Error)) -> ^Completion +send_all_tcp_poly3 :: #force_inline proc(socket: net.TCP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.TCP_Send_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - return _send_poly3(socket, buf, p, p2, p3, callback, all = true) + return _send_tcp_poly3(socket, buf, p, p2, p3, callback, all = true) } -send_all_udp_poly :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.Network_Error)) -> ^Completion +send_all_udp_poly :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, callback: $C/proc(p: T, sent: int, err: net.UDP_Send_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - return _send_poly(socket, buf, p, callback, endpoint, all = true) + return _send_udp_poly(socket, buf, p, callback, endpoint, all = true) } -send_all_udp_poly2 :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.Network_Error)) -> ^Completion +send_all_udp_poly2 :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, sent: int, err: net.UDP_Send_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - return _send_poly2(socket, buf, p, p2, callback, endpoint, all = true) + return _send_udp_poly2(socket, buf, p, p2, callback, endpoint, all = true) } -send_all_udp_poly3 :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.Network_Error)) -> ^Completion +send_all_udp_poly3 :: #force_inline proc(endpoint: net.Endpoint, socket: net.UDP_Socket, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, sent: int, err: net.UDP_Send_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - return _send_poly3(socket, buf, p, p2, p3, callback, endpoint, all = true) + return _send_udp_poly3(socket, buf, p, p2, p3, callback, endpoint, all = true) } /// Read Internal -_read_poly :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, read: int, err: os.Errno), all := false) -> ^Completion +_read_poly :: proc(fd: Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, read: int, err: FS_Error), all := false) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - completion := _read(io(), fd, offset, buf, nil, proc(completion: rawptr, read: int, err: os.Errno) { + completion := _read(io(), fd, offset, buf, nil, proc(completion: rawptr, read: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C)(rawptr(ptr))) p := unall((^T)(rawptr(ptr + size_of(C)))) @@ -428,9 +578,9 @@ _read_poly :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, callback: $C/ return completion } -_read_poly2 :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, read: int, err: os.Errno), all := false) -> ^Completion +_read_poly2 :: proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, read: int, err: FS_Error), all := false) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - completion := _read(io(), fd, offset, buf, nil, proc(completion: rawptr, read: int, err: os.Errno) { + completion := _read(io(), fd, offset, buf, nil, proc(completion: rawptr, read: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) @@ -448,9 +598,9 @@ _read_poly2 :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, cal return completion } -_read_poly3 :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, read: int, err: os.Errno), all := false) -> ^Completion +_read_poly3 :: proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, read: int, err: FS_Error), all := false) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - completion := _read(io(), fd, offset, buf, nil, proc(completion: rawptr, read: int, err: os.Errno) { + completion := _read(io(), fd, offset, buf, nil, proc(completion: rawptr, read: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) @@ -470,39 +620,39 @@ _read_poly3 :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: return completion } -read_at_poly :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, read: int, err: os.Errno)) -> ^Completion +read_at_poly :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, read: int, err: FS_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { return _read_poly(fd, offset, buf, p, callback) } -read_at_poly2 :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, read: int, err: os.Errno)) -> ^Completion +read_at_poly2 :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, read: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { return _read_poly2(fd, offset, buf, p, p2, callback) } -read_at_poly3 :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, read: int, err: os.Errno)) -> ^Completion +read_at_poly3 :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, read: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { return _read_poly3(fd, offset, buf, p, p2, p3, callback) } -read_at_all_poly :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, read: int, err: os.Errno)) -> ^Completion +read_at_all_poly :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, read: int, err: FS_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { return _read_poly(fd, offset, buf, p, callback, all = true) } -read_at_all_poly2 :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, read: int, err: os.Errno)) -> ^Completion +read_at_all_poly2 :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, read: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { return _read_poly2(fd, offset, buf, p, p2, callback, all = true) } -read_at_all_poly3 :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, read: int, err: os.Errno)) -> ^Completion +read_at_all_poly3 :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, read: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { return _read_poly3(fd, offset, buf, p, p2, p3, callback, all = true) } -_write_poly :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, written: int, err: os.Errno), all := false) -> ^Completion +_write_poly :: proc(fd: Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, written: int, err: FS_Error), all := false) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { - completion := _write(io(), fd, offset, buf, nil, proc(completion: rawptr, written: int, err: os.Errno) { + completion := _write(io(), fd, offset, buf, nil, proc(completion: rawptr, written: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C)(rawptr(ptr))) p := unall((^T)(rawptr(ptr + size_of(C)))) @@ -518,9 +668,9 @@ _write_poly :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, callback: $C return completion } -_write_poly2 :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, written: int, err: os.Errno), all := false) -> ^Completion +_write_poly2 :: proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, written: int, err: FS_Error), all := false) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { - completion := _write(io(), fd, offset, buf, nil, proc(completion: rawptr, written: int, err: os.Errno) { + completion := _write(io(), fd, offset, buf, nil, proc(completion: rawptr, written: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) @@ -538,9 +688,9 @@ _write_poly2 :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, ca return completion } -_write_poly3 :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, written: int, err: os.Errno), all := false) -> ^Completion +_write_poly3 :: proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, written: int, err: FS_Error), all := false) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { - completion := _write(io(), fd, offset, buf, nil, proc(completion: rawptr, written: int, err: os.Errno) { + completion := _write(io(), fd, offset, buf, nil, proc(completion: rawptr, written: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) p := unall((^T) (rawptr(ptr + size_of(C)))) @@ -560,37 +710,37 @@ _write_poly3 :: proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3 return completion } -write_at_poly :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, written: int, err: os.Errno)) -> ^Completion +write_at_poly :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, written: int, err: FS_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { return _write_poly(fd, offset, buf, p, callback) } -write_at_poly2 :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, written: int, err: os.Errno)) -> ^Completion +write_at_poly2 :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, written: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { return _write_poly2(fd, offset, buf, p, p2, callback) } -write_at_poly3 :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, written: int, err: os.Errno)) -> ^Completion +write_at_poly3 :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, written: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { return _write_poly3(fd, offset, buf, p, p2, p3, callback) } -write_at_all_poly :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, written: int, err: os.Errno)) -> ^Completion +write_at_all_poly :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, callback: $C/proc(p: T, written: int, err: FS_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { return _write_poly(fd, offset, buf, p, callback, all = true) } -write_at_all_poly2 :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, written: int, err: os.Errno)) -> ^Completion +write_at_all_poly2 :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, written: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { return _write_poly2(fd, offset, buf, p, p2, callback, all = true) } -write_at_all_poly3 :: #force_inline proc(fd: os.Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, written: int, err: os.Errno)) -> ^Completion +write_at_all_poly3 :: #force_inline proc(fd: Handle, offset: int, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, written: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { return _write_poly3(fd, offset, buf, p, p2, p3, callback, all = true) } -poll_poly :: proc(fd: os.Handle, event: Poll_Event, multi: bool, p: $T, callback: $C/proc(p: T, event: Poll_Event)) -> ^Completion +poll_poly :: proc(fd: Handle, event: Poll_Event, multi: bool, p: $T, callback: $C/proc(p: T, event: Poll_Event)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { completion := _poll(io(), fd, event, multi, nil, proc(completion: rawptr, event: Poll_Event) { ptr := uintptr(&((^Completion)(completion)).user_args) @@ -608,7 +758,7 @@ poll_poly :: proc(fd: os.Handle, event: Poll_Event, multi: bool, p: $T, callback return completion } -poll_poly2 :: proc(fd: os.Handle, event: Poll_Event, multi: bool, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, event: Poll_Event)) -> ^Completion +poll_poly2 :: proc(fd: Handle, event: Poll_Event, multi: bool, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, event: Poll_Event)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { completion := _poll(io(), fd, event, multi, nil, proc(completion: rawptr, event: Poll_Event) { ptr := uintptr(&((^Completion)(completion)).user_args) @@ -628,7 +778,7 @@ poll_poly2 :: proc(fd: os.Handle, event: Poll_Event, multi: bool, p: $T, p2: $T2 return completion } -poll_poly3 :: proc(fd: os.Handle, event: Poll_Event, multi: bool, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, event: Poll_Event)) -> ^Completion +poll_poly3 :: proc(fd: Handle, event: Poll_Event, multi: bool, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, event: Poll_Event)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { completion := _poll(io(), fd, event, multi, nil, proc(completion: rawptr, event: Poll_Event) { ptr := uintptr(&((^Completion)(completion)).user_args) diff --git a/core/nbio/entire_file.odin b/core/nbio/entire_file.odin index 6609248bfd5..8227c72cc5b 100644 --- a/core/nbio/entire_file.odin +++ b/core/nbio/entire_file.odin @@ -1,48 +1,41 @@ -#+build !js package nbio import "base:runtime" -import "core:os" - @(private="file") -read_entire_file_alloc :: proc(io: ^IO, fd: os.Handle, allocator: runtime.Allocator) -> (buf: []byte, err: os.Errno) { - size: i64 - if size, err = _file_size(io, fd); err != os.ERROR_NONE { - return - } - +read_entire_file_alloc :: proc(io: ^IO, fd: Handle, allocator: runtime.Allocator) -> (buf: []byte, err: FS_Error) { + size := _file_size(io, fd) or_return if size <= 0 { return } isize := int(size) if isize <= 0 { - err = os.ERROR_BUFFER_OVERFLOW when ODIN_OS == .Windows else os.EFBIG + err = .Overflow return } mem: runtime.Allocator_Error buf, mem = make([]byte, isize, allocator) if mem != nil { - err = os.ERROR_NOT_ENOUGH_MEMORY when ODIN_OS == .Windows else os.ENOMEM + err = .Allocation_Failed } return } -read_entire_file :: proc(fd: os.Handle, p: $T, callback: $C/proc(p: T, buf: []byte, err: os.Errno), allocator := context.allocator) -> ^Completion +read_entire_file :: proc(fd: Handle, p: $T, callback: $C/proc(p: T, buf: []byte, err: FS_Error), allocator := context.allocator) -> ^Completion where size_of(T) + size_of([]byte) <= MAX_USER_ARGUMENTS { io := io() buf, err := read_entire_file_alloc(io, fd, allocator) - if err != os.ERROR_NONE { + if err != nil { callback(p, nil, err) return nil } - completion := _read(io, fd, 0, buf, nil, proc(completion: rawptr, read: int, err: os.Errno) { + completion := _read(io, fd, 0, buf, nil, proc(completion: rawptr, read: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) buf := unall((^[]byte)(rawptr(ptr + size_of(C)))) @@ -60,18 +53,18 @@ read_entire_file :: proc(fd: os.Handle, p: $T, callback: $C/proc(p: T, buf: []by return completion } -read_entire_file2 :: proc(fd: os.Handle, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, buf: []byte, err: os.Errno), allocator := context.allocator) -> ^Completion +read_entire_file2 :: proc(fd: Handle, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, buf: []byte, err: FS_Error), allocator := context.allocator) -> ^Completion where size_of(T) + size_of(T2) + size_of([]byte) <= MAX_USER_ARGUMENTS { io := io() buf, err := read_entire_file_alloc(io, fd, allocator) - if err != os.ERROR_NONE { + if err != nil { callback(p, p2, nil, err) return nil } - completion := _read(io, fd, 0, buf, nil, proc(completion: rawptr, read: int, err: os.Errno) { + completion := _read(io, fd, 0, buf, nil, proc(completion: rawptr, read: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) buf := unall((^[]byte)(rawptr(ptr + size_of(C)))) @@ -91,18 +84,18 @@ read_entire_file2 :: proc(fd: os.Handle, p: $T, p2: $T2, callback: $C/proc(p: T, return completion } -read_entire_file3 :: proc(fd: os.Handle, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, buf: []byte, err: os.Errno), allocator := context.allocator) -> ^Completion +read_entire_file3 :: proc(fd: Handle, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, buf: []byte, err: FS_Error), allocator := context.allocator) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) + size_of([]byte) <= MAX_USER_ARGUMENTS { io := io() buf, err := read_entire_file_alloc(io, fd, allocator) - if err != os.ERROR_NONE { + if err != nil { callback(p, p2, p3, nil, err) return nil } - completion := _read(io, fd, 0, buf, nil, proc(completion: rawptr, read: int, err: os.Errno) { + completion := _read(io, fd, 0, buf, nil, proc(completion: rawptr, read: int, err: FS_Error) { ptr := uintptr(&((^Completion)(completion)).user_args) cb := unall((^C) (rawptr(ptr))) buf := unall((^[]byte)(rawptr(ptr + size_of(C)))) @@ -124,17 +117,17 @@ read_entire_file3 :: proc(fd: os.Handle, p: $T, p2: $T2, p3: $T3, callback: $C/p return completion } -write_entire_file :: #force_inline proc(fd: os.Handle, buf: []byte, p: $T, callback: $C/proc(p: T, written: int, err: os.Errno)) -> ^Completion +write_entire_file :: #force_inline proc(fd: Handle, buf: []byte, p: $T, callback: $C/proc(p: T, written: int, err: FS_Error)) -> ^Completion where size_of(T) <= MAX_USER_ARGUMENTS { return write_at_all_poly(fd, 0, buf, p, callback) } -write_entire_file2 :: #force_inline proc(fd: os.Handle, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, written: int, err: os.Errno)) -> ^Completion +write_entire_file2 :: #force_inline proc(fd: Handle, buf: []byte, p: $T, p2: $T2, callback: $C/proc(p: T, p2: T2, written: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) <= MAX_USER_ARGUMENTS { return write_at_all_poly2(fd, 0, buf, p, p2, callback) } -write_entire_file3 :: #force_inline proc(fd: os.Handle, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, written: int, err: os.Errno)) -> ^Completion +write_entire_file3 :: #force_inline proc(fd: Handle, buf: []byte, p: $T, p2: $T2, p3: $T3, callback: $C/proc(p: T, p2: T2, p3: T3, written: int, err: FS_Error)) -> ^Completion where size_of(T) + size_of(T2) + size_of(T3) <= MAX_USER_ARGUMENTS { return write_at_all_poly3(fd, 0, buf, p, p2, p3, callback) } diff --git a/core/nbio/errors.odin b/core/nbio/errors.odin new file mode 100644 index 00000000000..1cfd5cf404d --- /dev/null +++ b/core/nbio/errors.odin @@ -0,0 +1,57 @@ +package nbio + +import "base:intrinsics" + +import "core:net" + +Error :: intrinsics.type_merge( + net.Network_Error, + union #shared_nil { + General_Error, + FS_Error, + }, +) +#assert(size_of(Error) == 8) + +// Errors regarding general usage of the event loop. +General_Error :: enum i32 { + None, + + Allocation_Failed, + Unsupported = PLATFORM_ERR_UNSUPPORTED, +} + +// Errors gotten from file system operations. +FS_Error :: enum i32 { + None, + Allocation_Failed = PLATFORM_ERR_ALLOCATION_FAILED, + Timeout = PLATFORM_ERR_TIMEOUT, + Invalid_Argument = PLATFORM_ERR_INVALID_ARGUMENT, + Overflow = PLATFORM_ERR_OVERFLOW, + + // TODO: + // Permission_Denied = PLATFORM_ERR_PERMISSION_DENIED, + // Exist = PLATFORM_ERR_EXISTS, + // Not_Exist = PLATFORM_ERR_NOT_EXISTS, +} + +Platform_Error :: _Platform_Error + +/* +Returns the error as the underlying platform's error type. + +NOTE: usage of this means code is no longer cross-platform. +*/ +platform_error :: proc(err: Error) -> Platform_Error { + err := err + return (^Platform_Error)(&err)^ +} + +/* +Returns a string representation of the error. + +NOTE: returned string memory may be reused for subsequent calls and should be copied if held onto. +*/ +error_string :: proc(err: Error) -> string { + return _error_string(err) +} diff --git a/core/nbio/errors_posix.odin b/core/nbio/errors_posix.odin new file mode 100644 index 00000000000..3b46b75b8f9 --- /dev/null +++ b/core/nbio/errors_posix.odin @@ -0,0 +1,17 @@ +#+build darwin, openbsd, netbsd, freebsd +package nbio + +import "core:sys/posix" + +PLATFORM_ERR_UNSUPPORTED :: posix.ENOSYS + +PLATFORM_ERR_ALLOCATION_FAILED :: posix.ENOMEM +PLATFORM_ERR_TIMEOUT :: posix.ETIMEDOUT +PLATFORM_ERR_INVALID_ARGUMENT :: posix.EINVAL +PLATFORM_ERR_OVERFLOW :: posix.E2BIG + +_Platform_Error :: posix.Errno + +_error_string :: proc(err: Error) -> string { + return string(posix._strerror(platform_error(err))) +} diff --git a/core/nbio/nbio_internal.odin b/core/nbio/impl.odin similarity index 88% rename from core/nbio/nbio_internal.odin rename to core/nbio/impl.odin index 4cacfa404ba..15d4f4ffbfc 100644 --- a/core/nbio/nbio_internal.odin +++ b/core/nbio/impl.odin @@ -4,8 +4,6 @@ package nbio import "base:runtime" import "base:intrinsics" -import "core:os" - IO :: struct { using impl: _IO, initialized: bool, @@ -43,7 +41,7 @@ destroy_thread :: proc() { destroy(&g_io) } -init :: proc(io: ^IO, allocator := context.allocator) -> (err: os.Errno) { +init :: proc(io: ^IO, allocator := context.allocator) -> (err: General_Error) { return _init(io, allocator) } diff --git a/core/nbio/nbio_js.odin b/core/nbio/impl_js.odin similarity index 99% rename from core/nbio/nbio_js.odin rename to core/nbio/impl_js.odin index aab791ca4e4..2165bba1304 100644 --- a/core/nbio/nbio_js.odin +++ b/core/nbio/impl_js.odin @@ -1,3 +1,4 @@ +#+private package nbio import "base:runtime" diff --git a/core/nbio/nbio_linux.odin b/core/nbio/impl_linux.odin similarity index 99% rename from core/nbio/nbio_linux.odin rename to core/nbio/impl_linux.odin index 150c7e78d3d..8635f70d5bb 100644 --- a/core/nbio/nbio_linux.odin +++ b/core/nbio/impl_linux.odin @@ -1,3 +1,4 @@ +#+private package nbio import "core:container/queue" diff --git a/core/nbio/impl_os.odin b/core/nbio/impl_os.odin new file mode 100644 index 00000000000..ad5f1b28f59 --- /dev/null +++ b/core/nbio/impl_os.odin @@ -0,0 +1,80 @@ +#+build !js +#+private +package nbio + +import "base:runtime" + +import "core:container/queue" +import "core:mem" +import "core:mem/virtual" + +// TODO: this is a dumb thrown together pool, we should add a good one to `core` and use that. + +// An object pool where the objects are allocated on a growing arena. +Pool :: struct #no_copy { + arena: virtual.Arena, + objects_allocator: mem.Allocator, + objects: queue.Queue(^Completion), + // waiting: map[^T]struct{}, + num_waiting: int, +} + +@(require_results) +pool_init :: proc(p: ^Pool, cap := 8, allocator := context.allocator) -> (err: mem.Allocator_Error) { + virtual.arena_init_growing(&p.arena) or_return + defer if err != nil { virtual.arena_destroy(&p.arena) } + + p.objects_allocator = virtual.arena_allocator(&p.arena) + + queue.init(&p.objects, cap, allocator) or_return + defer if err != nil { + for elem in queue.pop_front_safe(&p.objects) { + free(elem, p.objects_allocator) + } + queue.destroy(&p.objects) + } + + for _ in 0 ..< cap { + completion := new(Completion, p.objects_allocator) or_return + + ok, perr := queue.push_back(&p.objects, completion) + assert(ok) + assert(perr == nil) + } + + return nil +} + +pool_destroy :: proc(p: ^Pool) { + for elem in queue.pop_front_safe(&p.objects) { + free(elem, p.objects_allocator) + } + virtual.arena_destroy(&p.arena) + queue.destroy(&p.objects) +} + +@(require_results) +pool_get :: proc(p: ^Pool) -> (completion: ^Completion) { + p.num_waiting += 1 + + ok: bool + completion, ok = queue.pop_front_safe(&p.objects) + if !ok { + err: runtime.Allocator_Error + if completion, err = new(Completion, p.objects_allocator); err != nil { + panic("nbio completion pool allocation error") + } + } + + return +} + +pool_put :: proc(p: ^Pool, elem: ^Completion) { + p.num_waiting -= 1 + assert(elem.operation != nil) + mem.zero_item(elem) + if _, err := queue.push_back(&p.objects, elem); err != nil { + panic("nbio completion pool allocation error") + } + return +} diff --git a/core/nbio/nbio_darwin.odin b/core/nbio/impl_posix.odin similarity index 65% rename from core/nbio/nbio_darwin.odin rename to core/nbio/impl_posix.odin index a53fc4f9737..e28ba1d39ce 100644 --- a/core/nbio/nbio_darwin.odin +++ b/core/nbio/impl_posix.odin @@ -1,27 +1,38 @@ +#+build darwin, netbsd, openbsd, freebsd +#+private package nbio -import "core:container/queue" -import "core:sys/posix" +import "base:runtime" + +import "core:container/queue" +import "core:net" +import "core:sys/posix" +import "core:time" import kq "core:sys/kqueue" -import "core:net" -import "core:os" -import "core:time" -_init :: proc(io: ^IO, allocator := context.allocator) -> (err: os.Errno) { +_init :: proc(io: ^IO, allocator := context.allocator) -> (err: General_Error) { qerr: posix.Errno io.kq, qerr = kq.kqueue() if qerr != .NONE { - return os.Platform_Error(qerr) + return General_Error(qerr) } + defer if err != nil { posix.close(io.kq) } - pool_init(&io.completion_pool, allocator = allocator) + perr: runtime.Allocator_Error + if perr = pool_init(&io.completion_pool, allocator = allocator); perr != nil { + err = .Allocation_Failed + return + } + defer if err != nil { pool_destroy(&io.completion_pool) } - io.timeouts = make([dynamic]^Completion, allocator) - io.io_pending = make([dynamic]^Completion, allocator) + io.timeouts.allocator = allocator + io.io_pending.allocator = allocator - queue.init(&io.completed, allocator = allocator) + if perr = queue.init(&io.completed, allocator = allocator); perr != nil { + err = .Allocation_Failed + return + } - io.allocator = allocator return } @@ -30,8 +41,6 @@ _num_waiting :: proc(io: ^IO) -> int { } _destroy :: proc(io: ^IO) { - context.allocator = io.allocator - delete(io.timeouts) delete(io.io_pending) @@ -46,14 +55,71 @@ _now :: proc(io: ^IO) -> time.Time { return io.now } -_tick :: proc(io: ^IO) -> os.Errno { +_tick :: proc(io: ^IO) -> General_Error { return flush(io) } -_listen :: proc(socket: net.TCP_Socket, backlog := 1000) -> net.Network_Error { - if errno := os.listen(os.Socket(socket), backlog); errno != nil { - return net.Listen_Error(errno.(os.Platform_Error)) +_open :: proc(_: ^IO, path: string, flags: File_Flags, perm: int) -> (handle: Handle, errno: FS_Error) { + if path == "" { + errno = .Invalid_Argument + return + } + + assert(len(path) <= posix.PATH_MAX) + buf: [posix.PATH_MAX+1]byte = --- + n := copy(buf[:], path) + buf[n+1] = 0 + + sys_flags := posix.O_Flags{.NOCTTY, .CLOEXEC, .NONBLOCK} + + if .Write in flags { + if .Read in flags { + sys_flags += {.RDWR} + } else { + sys_flags += {.WRONLY} + } } + + if .Append in flags { sys_flags += {.APPEND} } + if .Create in flags { sys_flags += {.CREAT} } + if .Excl in flags { sys_flags += {.EXCL} } + if .Sync in flags { sys_flags += {.DSYNC} } + if .Trunc in flags { sys_flags += {.TRUNC} } + if .Inheritable in flags { sys_flags -= {.CLOEXEC} } + + handle = posix.open(cstring(raw_data(buf[:])), sys_flags, transmute(posix.mode_t)posix._mode_t(perm)) + if handle < 0 { + errno = FS_Error(posix.errno()) + } + + return +} + +// // TODO: public `prepare_handle` and `prepare_socket` to take in a handle/socket from some other source? +// // (If that is possible on Windows). +// _prepare_handle :: proc(fd: Handle) -> FS_Error { +// res := posix.fcntl(fd, .GETFL, uintptr(0)) +// if res < 0 { +// return FS_Error(posix.errno()) +// } +// +// flags := transmute() +// } + +_file_size :: proc(_: ^IO, fd: Handle) -> (i64, FS_Error) { + stat: posix.stat_t + if posix.fstat(fd, &stat) != .OK { + return 0, FS_Error(posix.errno()) + } + + return i64(stat.st_size), nil +} + +_listen :: proc(socket: net.TCP_Socket, backlog := 1000) -> net.Listen_Error { + if res := posix.listen(posix.FD(socket), i32(backlog)); res != .OK { + return net.Listen_Error(posix.errno()) + } + return nil } @@ -71,12 +137,11 @@ _accept :: proc(io: ^IO, socket: net.TCP_Socket, user: rawptr, callback: On_Acce return completion } -// Wraps os.close using the kqueue. _close :: proc(io: ^IO, fd: Closable, user: rawptr, callback: On_Close) -> ^Completion { completion := pool_get(&io.completion_pool) - completion.ctx = context - completion.user_data = user + completion.ctx = context + completion.user_data = user completion.operation = Op_Close{ callback = callback, @@ -84,17 +149,16 @@ _close :: proc(io: ^IO, fd: Closable, user: rawptr, callback: On_Close) -> ^Comp op := &completion.operation.(Op_Close) switch h in fd { - case net.TCP_Socket: op.handle = os.Handle(h) - case net.UDP_Socket: op.handle = os.Handle(h) - case net.Socket: op.handle = os.Handle(h) - case os.Handle: op.handle = h + case net.TCP_Socket: op.handle = Handle(h) + case net.UDP_Socket: op.handle = Handle(h) + case net.Socket: op.handle = Handle(h) + case Handle: op.handle = h } - queue.push_back(&io.completed, completion) + push_completed(io, completion) return completion } -// TODO: maybe call this dial? _connect :: proc(io: ^IO, endpoint: net.Endpoint, user: rawptr, callback: On_Connect) -> (^Completion, net.Network_Error) { if endpoint.port == 0 { return nil, net.Dial_Error.Port_Required @@ -120,13 +184,13 @@ _connect :: proc(io: ^IO, endpoint: net.Endpoint, user: rawptr, callback: On_Con sockaddr = _endpoint_to_sockaddr(endpoint), } - queue.push_back(&io.completed, completion) + push_completed(io, completion) return completion, nil } _read :: proc( io: ^IO, - fd: os.Handle, + fd: Handle, offset: int, buf: []byte, user: rawptr, @@ -145,7 +209,7 @@ _read :: proc( len = len(buf), } - queue.push_back(&io.completed, completion) + push_completed(io, completion) return completion } @@ -161,7 +225,7 @@ _recv :: proc(io: ^IO, socket: net.Any_Socket, buf: []byte, user: rawptr, callba len = len(buf), } - queue.push_back(&io.completed, completion) + push_completed(io, completion) return completion } @@ -175,7 +239,7 @@ _send :: proc( all := false, ) -> ^Completion { if _, ok := socket.(net.UDP_Socket); ok { - assert(endpoint != nil) + assert(endpoint != nil, "send on UDP socket requires endpoint to send to") } completion := pool_get(&io.completion_pool) @@ -190,13 +254,13 @@ _send :: proc( len = len(buf), } - queue.push_back(&io.completed, completion) + push_completed(io, completion) return completion } _write :: proc( io: ^IO, - fd: os.Handle, + fd: Handle, offset: int, buf: []byte, user: rawptr, @@ -215,7 +279,7 @@ _write :: proc( len = len(buf), } - queue.push_back(&io.completed, completion) + push_completed(io, completion) return completion } @@ -229,7 +293,7 @@ _timeout :: proc(io: ^IO, dur: time.Duration, user: rawptr, callback: On_Timeout expires = time.time_add(io.now, dur), } - append(&io.timeouts, completion) + push_timeout(io, completion) return completion } @@ -250,7 +314,8 @@ _timeout_completion :: proc(io: ^IO, dur: time.Duration, target: ^Completion) -> expires = time.time_add(io.now, dur), } target.timeout = completion - append(&io.timeouts, completion) + + push_timeout(io, completion) return completion } @@ -282,7 +347,7 @@ _remove :: proc(io: ^IO, target: ^Completion) { target = target, } - append(&io.io_pending, completion) + push_pending(io, completion) } _next_tick :: proc(io: ^IO, user: rawptr, callback: On_Next_Tick) -> ^Completion { @@ -293,11 +358,11 @@ _next_tick :: proc(io: ^IO, user: rawptr, callback: On_Next_Tick) -> ^Completion callback = callback, } - queue.push_back(&io.completed, completion) + push_completed(io, completion) return completion } -_poll :: proc(io: ^IO, fd: os.Handle, event: Poll_Event, multi: bool, user: rawptr, callback: On_Poll) -> ^Completion { +_poll :: proc(io: ^IO, fd: Handle, event: Poll_Event, multi: bool, user: rawptr, callback: On_Poll) -> ^Completion { completion := pool_get(&io.completion_pool) completion.ctx = context @@ -309,6 +374,6 @@ _poll :: proc(io: ^IO, fd: os.Handle, event: Poll_Event, multi: bool, user: rawp multi = multi, } - append(&io.io_pending, completion) + push_pending(io, completion) return completion } diff --git a/core/nbio/impl_unix.odin b/core/nbio/impl_unix.odin new file mode 100644 index 00000000000..e067ceab98f --- /dev/null +++ b/core/nbio/impl_unix.odin @@ -0,0 +1,34 @@ +#+build darwin, netbsd, openbsd, freebsd, linux +#+private +package nbio + +import "core:net" + +_open_socket :: proc( + _: ^IO, + family: net.Address_Family, + protocol: net.Socket_Protocol, +) -> ( + socket: net.Any_Socket, + err: net.Network_Error, +) { + socket = net.create_socket(family, protocol) or_return + + err = _prepare_socket(socket) + if err != nil { net.close(socket) } + return +} + +// TODO: public `prepare_handle` and `prepare_socket` to take in a handle/socket from some other source? +// (If that is possible on Windows). +_prepare_socket :: proc(socket: net.Any_Socket) -> net.Network_Error { + net.set_option(socket, .Reuse_Address, true) or_return + + // TODO; benchmark this, even if faster it is prob not to be turned on + // by default here, maybe by default for the server, but I don't think this + // will be faster/more efficient. + // net.set_option(socket, .TCP_Nodelay, true) or_return + + net.set_blocking(socket, false) or_return + return nil +} diff --git a/core/nbio/nbio_windows.odin b/core/nbio/impl_windows.odin similarity index 99% rename from core/nbio/nbio_windows.odin rename to core/nbio/impl_windows.odin index cf4884ee14b..74a2e89d905 100644 --- a/core/nbio/nbio_windows.odin +++ b/core/nbio/impl_windows.odin @@ -1,3 +1,4 @@ +#+private package nbio import "core:container/queue" diff --git a/core/nbio/nbio_internal_linux.odin b/core/nbio/internal_linux.odin similarity index 100% rename from core/nbio/nbio_internal_linux.odin rename to core/nbio/internal_linux.odin diff --git a/core/nbio/nbio_internal_darwin.odin b/core/nbio/internal_posix.odin similarity index 63% rename from core/nbio/nbio_internal_darwin.odin rename to core/nbio/internal_posix.odin index 633278d8c3c..9c9d84c32b3 100644 --- a/core/nbio/nbio_internal_darwin.odin +++ b/core/nbio/internal_posix.odin @@ -1,15 +1,14 @@ +#+build darwin, openbsd, netbsd, freebsd #+private package nbio -import "base:runtime" +import "base:runtime" -import "core:container/queue" -import "core:mem" +import "core:container/queue" +import "core:net" +import "core:sys/posix" +import "core:time" import kq "core:sys/kqueue" -import "core:sys/posix" -import "core:net" -import "core:os" -import "core:time" MAX_EVENTS :: 256 @@ -23,10 +22,11 @@ _IO :: struct #no_copy { timeouts: [dynamic]^Completion, completed: queue.Queue(^Completion), io_pending: [dynamic]^Completion, - allocator: mem.Allocator, now: time.Time, } +_Handle :: posix.FD + _Completion :: struct { operation: Operation, timeout: ^Completion, @@ -41,13 +41,13 @@ Op_Accept :: struct { Op_Close :: struct { callback: On_Close, - handle: os.Handle, + handle: Handle, } Op_Connect :: struct { callback: On_Connect, socket: net.TCP_Socket, - sockaddr: os.SOCKADDR_STORAGE_LH, + sockaddr: posix.sockaddr_storage, initiated: bool, } @@ -72,7 +72,7 @@ Op_Send :: struct { Op_Read :: struct { callback: On_Read, - fd: os.Handle, + fd: Handle, buf: []byte, offset: int, all: bool, @@ -82,7 +82,7 @@ Op_Read :: struct { Op_Write :: struct { callback: On_Write, - fd: os.Handle, + fd: Handle, buf: []byte, offset: int, all: bool, @@ -101,7 +101,7 @@ Op_Next_Tick :: struct { Op_Poll :: struct { callback: On_Poll, - fd: os.Handle, + fd: Handle, event: Poll_Event, multi: bool, } @@ -110,7 +110,33 @@ Op_Remove :: struct { target: ^Completion, } -flush :: proc(io: ^IO) -> os.Errno { +push_completed :: proc(io: ^IO, completed: ^Completion) { + ok, err := queue.push_back(&io.completed, completed) + if !ok || err != nil { + panic("nbio completed queue allocation failure") + } +} + +push_timeout :: proc(io: ^IO, completion: ^Completion) { + when !ODIN_DISABLE_ASSERT { + _, is_timeout := completion.operation.(Op_Timeout) + assert(is_timeout) + } + + _, err := append(&io.timeouts, completion) + if err != nil { + panic("nbio timeout queue allocation failure") + } +} + +push_pending :: proc(io: ^IO, completion: ^Completion) { + _, err := append(&io.io_pending, completion) + if err != nil { + panic("nbio pending queue allocation failure") + } +} + +flush :: proc(io: ^IO) -> General_Error { defer assert(io.io_inflight >= 0) events: [MAX_EVENTS]kq.KEvent @@ -120,7 +146,7 @@ flush :: proc(io: ^IO) -> os.Errno { if (change_events > 0 || queue.len(io.completed) == 0) { if (change_events == 0 && queue.len(io.completed) == 0 && io.io_inflight == 0) { - return os.ERROR_NONE + return nil } max_timeout := time.Millisecond * 10 @@ -134,7 +160,7 @@ flush :: proc(io: ^IO) -> os.Errno { assert(new_events == 0) continue } else if err != nil { - return os.Platform_Error(err) + return General_Error(err) } else { break } @@ -152,7 +178,7 @@ flush :: proc(io: ^IO) -> os.Errno { for event in events[:new_events] { completion := cast(^Completion)event.udata completion.in_kernel = false - queue.push_back(&io.completed, completion) + push_completed(io, completion) } } } @@ -193,13 +219,23 @@ time_out_op :: proc(io: ^IO, completed: ^Completion) { context = completed.ctx switch &op in completed.operation { case Op_Accept: op.callback(completed.user_data, {}, {}, net.Accept_Error.Would_Block) - case Op_Close: op.callback(completed.user_data, false) + case Op_Close: op.callback(completed.user_data, .Timeout) case Op_Connect: op.callback(completed.user_data, {}, net.Dial_Error.Timeout) - case Op_Read: op.callback(completed.user_data, 0, os.EWOULDBLOCK) - case Op_Recv: op.callback(completed.user_data, 0, nil, net.UDP_Recv_Error.Timeout) // TODO: may be tcp - case Op_Send: op.callback(completed.user_data, 0, net.UDP_Send_Error.Timeout) // TODO: may be tcp - case Op_Write: op.callback(completed.user_data, 0, os.EWOULDBLOCK) - case Op_Poll: op.callback(completed.user_data, nil) + case Op_Read: op.callback(completed.user_data, 0, .Timeout) + case Op_Recv: + switch cb in op.callback { + case On_Recv_TCP: cb(completed.user_data, 0, net.TCP_Recv_Error.Timeout) + case On_Recv_UDP: cb(completed.user_data, 0, {}, net.UDP_Recv_Error.Timeout) + case: unreachable() + } + case Op_Send: + switch cb in op.callback { + case On_Sent_TCP: cb(completed.user_data, 0, net.TCP_Send_Error.Timeout) + case On_Sent_UDP: cb(completed.user_data, 0, net.UDP_Send_Error.Timeout) + case: unreachable() + } + case Op_Write: op.callback(completed.user_data, 0, .Timeout) + case Op_Poll: op.callback(completed.user_data, nil) // TODO: add error to callback case Op_Timeout, Op_Next_Tick, Op_Remove: panic("timed out untimeoutable") case: unreachable() } @@ -241,10 +277,10 @@ flush_io :: proc(io: ^IO, events: []kq.KEvent) -> (changed_events: int, completi event.ident = uintptr(op.fd) event.filter = .Write case Op_Recv: - event.ident = uintptr(os.Socket(net.any_socket_to_socket(op.socket))) + event.ident = uintptr(net.any_socket_to_socket(op.socket)) event.filter = .Read case Op_Send: - event.ident = uintptr(os.Socket(net.any_socket_to_socket(op.socket))) + event.ident = uintptr(net.any_socket_to_socket(op.socket)) event.filter = .Write case Op_Poll: event.ident = uintptr(op.fd) @@ -277,10 +313,10 @@ flush_io :: proc(io: ^IO, events: []kq.KEvent) -> (changed_events: int, completi event.ident = uintptr(inner_op.fd) event.filter = .Write case Op_Recv: - event.ident = uintptr(os.Socket(net.any_socket_to_socket(inner_op.socket))) + event.ident = uintptr(net.any_socket_to_socket(inner_op.socket)) event.filter = .Read case Op_Send: - event.ident = uintptr(os.Socket(net.any_socket_to_socket(inner_op.socket))) + event.ident = uintptr(net.any_socket_to_socket(inner_op.socket)) event.filter = .Write case Op_Poll: event.ident = uintptr(inner_op.fd) @@ -342,7 +378,7 @@ flush_timeouts :: proc(io: ^IO) -> (min_timeout: Maybe(i64)) { do_accept :: proc(io: ^IO, completion: ^Completion, op: ^Op_Accept) { client, source, err := net.accept_tcp(op.sock) if err == net.Accept_Error.Would_Block { - append(&io.io_pending, completion) + push_pending(io, completion) return } @@ -352,7 +388,7 @@ do_accept :: proc(io: ^IO, completion: ^Completion, op: ^Op_Accept) { if err != nil { net.close(client) - op.callback(completion.user_data, {}, {}, err) + op.callback(completion.user_data, {}, {}, err.(net.Accept_Error)) } else { op.callback(completion.user_data, client, source, nil) } @@ -361,31 +397,33 @@ do_accept :: proc(io: ^IO, completion: ^Completion, op: ^Op_Accept) { } do_close :: proc(io: ^IO, completion: ^Completion, op: ^Op_Close) { - ok := os.close(op.handle) - - op.callback(completion.user_data, ok == nil) - + res := posix.close(op.handle) + op.callback(completion.user_data, FS_Error(posix.errno()) if res != .OK else nil) pool_put(&io.completion_pool, completion) } do_connect :: proc(io: ^IO, completion: ^Completion, op: ^Op_Connect) { defer op.initiated = true - err: os.Errno + err: posix.Errno if op.initiated { // We have already called os.connect, retrieve error number only. - os.getsockopt(os.Socket(op.socket), os.SOL_SOCKET, os.SO_ERROR, &err, size_of(os.Errno)) + size := posix.socklen_t(size_of(err)) + posix.getsockopt(posix.FD(op.socket), posix.SOL_SOCKET, .ERROR, &err, &size) } else { - err = os.connect(os.Socket(op.socket), (^os.SOCKADDR)(&op.sockaddr), i32(op.sockaddr.len)) - if err == os.EINPROGRESS { - append(&io.io_pending, completion) - return + res := posix.connect(posix.FD(op.socket), (^posix.sockaddr)(&op.sockaddr), posix.socklen_t(op.sockaddr.ss_len)) + if res != .OK { + err = posix.errno() + if err == .EINPROGRESS { + push_pending(io, completion) + return + } } } - if err != os.ERROR_NONE { + if err != nil { net.close(op.socket) - op.callback(completion.user_data, {}, net.Dial_Error(err.(os.Platform_Error))) + op.callback(completion.user_data, {}, net.Dial_Error(err)) } else { op.callback(completion.user_data, op.socket, nil) } @@ -394,20 +432,21 @@ do_connect :: proc(io: ^IO, completion: ^Completion, op: ^Op_Connect) { } do_read :: proc(io: ^IO, completion: ^Completion, op: ^Op_Read) { - read, err := os.read_at(op.fd, op.buf, i64(op.offset)) - op.read += read - - if err != os.ERROR_NONE { - if err == os.EWOULDBLOCK { - append(&io.io_pending, completion) + read := posix.pread(op.fd, raw_data(op.buf), len(op.buf), posix.off_t(op.offset)) + if read < 0 { + err := posix.errno() + if err == .EWOULDBLOCK { + push_pending(io, completion) return } - op.callback(completion.user_data, op.read, err) + op.callback(completion.user_data, op.read, FS_Error(err)) pool_put(&io.completion_pool, completion) return } + op.read += read + if op.all && op.read < op.len { op.buf = op.buf[read:] op.offset += read @@ -416,51 +455,69 @@ do_read :: proc(io: ^IO, completion: ^Completion, op: ^Op_Read) { return } - op.callback(completion.user_data, op.read, os.ERROR_NONE) + op.callback(completion.user_data, op.read, nil) pool_put(&io.completion_pool, completion) } do_recv :: proc(io: ^IO, completion: ^Completion, op: ^Op_Recv) { - received: int - err: net.Network_Error - remote_endpoint: Maybe(net.Endpoint) + // received: int + // err: net.Network_Error + // remote_endpoint: Maybe(net.Endpoint) switch sock in op.socket { case net.TCP_Socket: - received, err = net.recv_tcp(sock, op.buf) + received, err := net.recv_tcp(sock, op.buf) + if err != nil { + // NOTE: Timeout is the name for EWOULDBLOCK in net package. + if err == net.TCP_Recv_Error.Timeout { + push_pending(io, completion) + return + } - // NOTE: Timeout is the name for EWOULDBLOCK in net package. - if err == net.TCP_Recv_Error.Timeout { - append(&io.io_pending, completion) + maybe_cancel_timeout(completion) + op.callback.(On_Recv_TCP)(completion.user_data, op.received, err.(net.TCP_Recv_Error)) + pool_put(&io.completion_pool, completion) return } + + op.received += received + + if op.all && op.received < op.len { + op.buf = op.buf[received:] + do_recv(io, completion, op) + return + } + + maybe_cancel_timeout(completion) + op.callback.(On_Recv_TCP)(completion.user_data, op.received, nil) + pool_put(&io.completion_pool, completion) + case net.UDP_Socket: - received, remote_endpoint, err = net.recv_udp(sock, op.buf) + received, remote_endpoint, err := net.recv_udp(sock, op.buf) + if err != nil { + // NOTE: Timeout is the name for EWOULDBLOCK in net package. + if err == net.UDP_Recv_Error.Timeout { + push_pending(io, completion) + return + } - // NOTE: Timeout is the name for EWOULDBLOCK in net package. - if err == net.UDP_Recv_Error.Timeout { - append(&io.io_pending, completion) + maybe_cancel_timeout(completion) + op.callback.(On_Recv_UDP)(completion.user_data, op.received, remote_endpoint, err.(net.UDP_Recv_Error)) + pool_put(&io.completion_pool, completion) return } - } - op.received += received + op.received += received + + if op.all && op.received < op.len { + op.buf = op.buf[received:] + do_recv(io, completion, op) + return + } - if err != nil { maybe_cancel_timeout(completion) - op.callback(completion.user_data, op.received, remote_endpoint, err) + op.callback.(On_Recv_UDP)(completion.user_data, op.received, remote_endpoint, nil) pool_put(&io.completion_pool, completion) - return - } - - if op.all && op.received < op.len { - op.buf = op.buf[received:] - do_recv(io, completion, op) - return } - - maybe_cancel_timeout(completion) - op.callback(completion.user_data, op.received, remote_endpoint, err) - pool_put(&io.completion_pool, completion) } maybe_cancel_timeout :: #force_inline proc(completion: ^Completion) { @@ -471,67 +528,82 @@ maybe_cancel_timeout :: #force_inline proc(completion: ^Completion) { } do_send :: proc(io: ^IO, completion: ^Completion, op: ^Op_Send) { - sent: u32 - errno: os.Errno - err: net.Network_Error - switch sock in op.socket { case net.TCP_Socket: - sent, errno = os.send(os.Socket(sock), op.buf, os.MSG_NOSIGNAL) - if errno == os.EPIPE { - err = net.TCP_Send_Error.Connection_Closed - } else if errno != nil { - err = net.TCP_Send_Error(errno.(os.Platform_Error)) + sent := posix.send(posix.FD(sock), raw_data(op.buf), len(op.buf), {.NOSIGNAL}) + if sent < 0 { + errno := posix.errno() + err := net.TCP_Send_Error(errno) + if errno == .EPIPE { + err = net.TCP_Send_Error.Connection_Closed + } else if errno == .EWOULDBLOCK { + push_pending(io, completion) + return + } + + op.callback.(On_Sent_TCP)(completion.user_data, op.sent, err) + pool_put(&io.completion_pool, completion) + return + } + + op.sent += sent + + if op.all && op.sent < op.len { + op.buf = op.buf[sent:] + do_send(io, completion, op) + return } + op.callback.(On_Sent_TCP)(completion.user_data, op.sent, nil) + pool_put(&io.completion_pool, completion) + case net.UDP_Socket: toaddr := _endpoint_to_sockaddr(op.endpoint.(net.Endpoint)) - sent, errno = os.sendto(os.Socket(sock), op.buf, os.MSG_NOSIGNAL, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) - if errno == os.EPIPE { - err = net.UDP_Send_Error.Not_Socket - } else if errno != nil { - err = net.UDP_Send_Error(errno.(os.Platform_Error)) + sent := posix.sendto(posix.FD(sock), raw_data(op.buf), len(op.buf), {.NOSIGNAL}, (^posix.sockaddr)(&toaddr), posix.socklen_t(toaddr.ss_len)) + if sent < 0 { + errno := posix.errno() + err := net.UDP_Send_Error(errno) + if errno == .EPIPE { + err = net.UDP_Send_Error.Not_Socket + } else if errno == .EWOULDBLOCK { + push_pending(io, completion) + return + } + + op.callback.(On_Sent_UDP)(completion.user_data, op.sent, err) + pool_put(&io.completion_pool, completion) + return } - } - op.sent += int(sent) + op.sent += sent - if errno != os.ERROR_NONE { - if errno == os.EWOULDBLOCK { - append(&io.io_pending, completion) + if op.all && op.sent < op.len { + op.buf = op.buf[sent:] + do_send(io, completion, op) return } - op.callback(completion.user_data, op.sent, err) + op.callback.(On_Sent_UDP)(completion.user_data, op.sent, nil) pool_put(&io.completion_pool, completion) - return } - - if op.all && op.sent < op.len { - op.buf = op.buf[sent:] - do_send(io, completion, op) - return - } - - op.callback(completion.user_data, op.sent, nil) - pool_put(&io.completion_pool, completion) } do_write :: proc(io: ^IO, completion: ^Completion, op: ^Op_Write) { - written, err := os.write_at(op.fd, op.buf, i64(op.offset)) - op.written += written - - if err != os.ERROR_NONE { - if err == os.EWOULDBLOCK { - append(&io.io_pending, completion) + written := posix.pwrite(op.fd, raw_data(op.buf), len(op.buf), posix.off_t(op.offset)) + if written < 0 { + err := posix.errno() + if err == .EWOULDBLOCK { + push_pending(io, completion) return } - op.callback(completion.user_data, op.written, err) + op.callback(completion.user_data, op.written, FS_Error(err)) pool_put(&io.completion_pool, completion) return } + op.written += written + // The write did not write the whole buffer, need to write more. if op.all && op.written < op.len { op.buf = op.buf[written:] @@ -541,7 +613,7 @@ do_write :: proc(io: ^IO, completion: ^Completion, op: ^Op_Write) { return } - op.callback(completion.user_data, op.written, os.ERROR_NONE) + op.callback(completion.user_data, op.written, nil) pool_put(&io.completion_pool, completion) } @@ -589,22 +661,22 @@ do_next_tick :: proc(io: ^IO, completion: ^Completion, op: ^Op_Next_Tick) { } // Private proc in net package, verbatim copy. -_endpoint_to_sockaddr :: proc(ep: net.Endpoint) -> (sockaddr: os.SOCKADDR_STORAGE_LH) { +_endpoint_to_sockaddr :: proc(ep: net.Endpoint) -> (sockaddr: posix.sockaddr_storage) { switch a in ep.address { case net.IP4_Address: - (^os.sockaddr_in)(&sockaddr)^ = os.sockaddr_in { + (^posix.sockaddr_in)(&sockaddr)^ = posix.sockaddr_in { sin_port = u16be(ep.port), - sin_addr = transmute(os.in_addr)a, - sin_family = u8(os.AF_INET), - sin_len = size_of(os.sockaddr_in), + sin_addr = transmute(posix.in_addr)a, + sin_family = .INET, + sin_len = size_of(posix.sockaddr_in), } return case net.IP6_Address: - (^os.sockaddr_in6)(&sockaddr)^ = os.sockaddr_in6 { + (^posix.sockaddr_in6)(&sockaddr)^ = posix.sockaddr_in6 { sin6_port = u16be(ep.port), - sin6_addr = transmute(os.in6_addr)a, - sin6_family = u8(os.AF_INET6), - sin6_len = size_of(os.sockaddr_in6), + sin6_addr = transmute(posix.in6_addr)a, + sin6_family = .INET6, + sin6_len = size_of(posix.sockaddr_in6), } return } diff --git a/core/nbio/nbio_internal_windows.odin b/core/nbio/internal_windows.odin similarity index 100% rename from core/nbio/nbio_internal_windows.odin rename to core/nbio/internal_windows.odin diff --git a/core/nbio/nbio_unix.odin b/core/nbio/nbio_unix.odin deleted file mode 100644 index 9eea415bd27..00000000000 --- a/core/nbio/nbio_unix.odin +++ /dev/null @@ -1,55 +0,0 @@ -#+build darwin, linux -#+private -package nbio - -import "core:net" -import "core:os" - -_open :: proc(_: ^IO, path: string, mode, perm: int) -> (handle: os.Handle, errno: os.Errno) { - handle, errno = os.open(path, mode, perm) - if errno != os.ERROR_NONE { return } - - errno = _prepare_handle(handle) - if errno != os.ERROR_NONE { os.close(handle) } - return -} - -_file_size :: proc(_: ^IO, fd: os.Handle) -> (i64, os.Errno) { - return os.file_size(fd) -} - -_prepare_handle :: proc(fd: os.Handle) -> os.Errno { - // NOTE: TCP_Socket gets cast to int right away in net, so this is safe to do. - if err := net.set_blocking(net.TCP_Socket(fd), false); err != nil { - return os.Platform_Error(err.(net.Set_Blocking_Error)) - } - return os.ERROR_NONE -} - -_open_socket :: proc( - _: ^IO, - family: net.Address_Family, - protocol: net.Socket_Protocol, -) -> ( - socket: net.Any_Socket, - err: net.Network_Error, -) { - socket, err = net.create_socket(family, protocol) - if err != nil { return } - - err = _prepare_socket(socket) - if err != nil { net.close(socket) } - return -} - -_prepare_socket :: proc(socket: net.Any_Socket) -> net.Network_Error { - net.set_option(socket, .Reuse_Address, true) or_return - - // TODO; benchmark this, even if faster it is prob not to be turned on - // by default here, maybe by default for the server, but I don't think this - // will be faster/more efficient. - // net.set_option(socket, .TCP_Nodelay, true) or_return - - net.set_blocking(socket, false) or_return - return nil -} diff --git a/core/nbio/pool.odin b/core/nbio/pool.odin deleted file mode 100644 index 0640d875958..00000000000 --- a/core/nbio/pool.odin +++ /dev/null @@ -1,58 +0,0 @@ -#+build !js -#+private -package nbio - -import "core:container/queue" -import "core:mem" -import "core:mem/virtual" - -// TODO: this is a dumb thrown together pool, we should add a good one to `core` and use that. - -// An object pool where the objects are allocated on a growing arena. -Pool :: struct { - arena: virtual.Arena, - objects_allocator: mem.Allocator, - objects: queue.Queue(^Completion), - // waiting: map[^T]struct{}, - num_waiting: int, -} - -DEFAULT_STARTING_CAP :: 8 - -pool_init :: proc(p: ^Pool, cap := DEFAULT_STARTING_CAP, allocator := context.allocator) -> mem.Allocator_Error { - virtual.arena_init_growing(&p.arena) or_return - p.objects_allocator = virtual.arena_allocator(&p.arena) - - queue.init(&p.objects, cap, allocator) or_return - for _ in 0 ..< cap { - _ = queue.push_back(&p.objects, new(Completion, p.objects_allocator)) or_return - } - - return nil -} - -pool_destroy :: proc(p: ^Pool) { - virtual.arena_destroy(&p.arena) - queue.destroy(&p.objects) -} - -pool_get :: proc(p: ^Pool) -> (^Completion, mem.Allocator_Error) #optional_allocator_error { - p.num_waiting += 1 - - elem, ok := queue.pop_front_safe(&p.objects) - if !ok { - return new(Completion, p.objects_allocator) - } - - // p.waiting[elem] = {} - - return elem, nil -} - -pool_put :: proc(p: ^Pool, elem: ^Completion) -> mem.Allocator_Error { - p.num_waiting -= 1 - assert(elem.operation != nil) - mem.zero_item(elem) - _, err := queue.push_back(&p.objects, elem) - return err -} diff --git a/tests/core/nbio/cases.odin b/tests/core/nbio/cases.odin index 57ffa58fc4e..eafd49f4f21 100644 --- a/tests/core/nbio/cases.odin +++ b/tests/core/nbio/cases.odin @@ -38,11 +38,11 @@ open_next_available_local_port :: proc(t: ^testing.T, loc := #caller_location) - @(test) close_invalid_handle_works :: proc(t: ^testing.T) { - nbio.close_poly(os.INVALID_HANDLE, t, proc(t: ^testing.T, ok: bool) { - ev(t, ok, false) + nbio.close_poly(nbio.Handle(os.INVALID_HANDLE), t, proc(t: ^testing.T, err: nbio.FS_Error) { + e(t, err != nil) }) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) } @(test) @@ -51,7 +51,7 @@ timeout_runs_in_reasonable_time :: proc(t: ^testing.T) { nbio.timeout(time.Millisecond * 10, rawptr(nil), proc(_: rawptr) {}) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) duration := time.since(start) e(t, duration < time.Millisecond * 11) @@ -61,14 +61,14 @@ timeout_runs_in_reasonable_time :: proc(t: ^testing.T) { write_read_close :: proc(t: ^testing.T) { handle, errno := nbio.open( "test_write_read_close", - os.O_RDWR | os.O_CREATE | os.O_TRUNC, - os.S_IRUSR | os.S_IWUSR | os.S_IRGRP | os.S_IROTH when ODIN_OS != .Windows else 0, + {.Read, .Write, .Create, .Trunc}, + 0o777, ) - ev(t, errno, os.ERROR_NONE) + ev(t, errno, nil) State :: struct { buf: [20]byte, - fd: os.Handle, + fd: nbio.Handle, } CONTENT :: [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} @@ -78,23 +78,23 @@ write_read_close :: proc(t: ^testing.T) { fd = handle, } - nbio.write_entire_file2(handle, state.buf[:], t, &state, proc(t: ^testing.T, state: ^State, written: int, err: os.Errno) { + nbio.write_entire_file2(handle, state.buf[:], t, &state, proc(t: ^testing.T, state: ^State, written: int, err: nbio.FS_Error) { ev(t, written, len(state.buf)) - ev(t, err, os.ERROR_NONE) + ev(t, err, nil) - nbio.read_at_all_poly2(state.fd, 0, state.buf[:], t, state, proc(t: ^testing.T, state: ^State, read: int, err: os.Errno) { + nbio.read_at_all_poly2(state.fd, 0, state.buf[:], t, state, proc(t: ^testing.T, state: ^State, read: int, err: nbio.FS_Error) { ev(t, read, len(state.buf)) - ev(t, err, os.ERROR_NONE) + ev(t, err, nil) ev(t, state.buf, CONTENT) - nbio.close_poly2(state.fd, t, state, proc(t: ^testing.T, state: ^State, ok: bool) { - ev(t, ok, true) + nbio.close_poly2(state.fd, t, state, proc(t: ^testing.T, state: ^State, err: nbio.FS_Error) { + ev(t, err, nil) os.remove("test_write_read_close") }) }) }) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) } @(test) @@ -116,16 +116,16 @@ client_and_server_send_recv :: proc(t: ^testing.T) { send_buf = CONTENT, } - close_ok :: proc(t: ^testing.T, ok: bool) { - ev(t, ok, true) + close_ok :: proc(t: ^testing.T, err: nbio.FS_Error) { + ev(t, err, nil) } - nbio.accept_poly2(server, t, &state, proc(t: ^testing.T, state: ^State, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + nbio.accept_poly2(server, t, &state, proc(t: ^testing.T, state: ^State, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ev(t, err, nil) state.server_client = client - nbio.recv_all_poly2(client, state.recv_buf[:], t, state, proc(t: ^testing.T, state: ^State, received: int, _: Maybe(net.Endpoint), err: net.Network_Error) { + nbio.recv_all_tcp_poly2(client, state.recv_buf[:], t, state, proc(t: ^testing.T, state: ^State, received: int, err: net.TCP_Recv_Error) { ev(t, err, nil) ev(t, received, 20) ev(t, state.recv_buf, CONTENT) @@ -135,14 +135,14 @@ client_and_server_send_recv :: proc(t: ^testing.T) { }) }) - ev(t, nbio.tick(), os.ERROR_NONE) + ev(t, nbio.tick(), nil) nbio.connect_poly2(ep, t, &state, proc(t: ^testing.T, state: ^State, socket: net.TCP_Socket, err: net.Network_Error) { ev(t, err, nil) state.client = socket - nbio.send_all_tcp_poly2(socket, state.send_buf[:], t, state, proc(t: ^testing.T, state: ^State, sent: int, err: net.Network_Error) { + nbio.send_all_tcp_poly2(socket, state.send_buf[:], t, state, proc(t: ^testing.T, state: ^State, sent: int, err: net.TCP_Send_Error) { ev(t, err, nil) ev(t, sent, 20) @@ -150,88 +150,88 @@ client_and_server_send_recv :: proc(t: ^testing.T) { }) }) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) } @(test) close_and_remove_accept :: proc(t: ^testing.T) { server, _ := open_next_available_local_port(t) - accept := nbio.accept_poly(server, t, proc(t: ^testing.T, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + accept := nbio.accept_poly(server, t, proc(t: ^testing.T, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { testing.fail_now(t) }) - ev(t, nbio.tick(), os.ERROR_NONE) + ev(t, nbio.tick(), nil) - nbio.close_poly(server, t, proc(t: ^testing.T, ok: bool) { - ev(t, ok, true) + nbio.close_poly(server, t, proc(t: ^testing.T, err: nbio.FS_Error) { + ev(t, err, nil) }) nbio.remove(accept) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) } @(test) close_errors_recv :: proc(t: ^testing.T) { server, ep := open_next_available_local_port(t) - nbio.accept_poly(server, t, proc(t: ^testing.T, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + nbio.accept_poly(server, t, proc(t: ^testing.T, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ev(t, err, nil) bytes := make([]byte, 128, context.temp_allocator) - nbio.recv_poly(client, bytes, t, proc(t: ^testing.T, received: int, _: Maybe(net.Endpoint), err: net.Network_Error) { + nbio.recv_tcp_poly(client, bytes, t, proc(t: ^testing.T, received: int, err: net.TCP_Recv_Error) { ev(t, received, 0) ev(t, err, nil) }) }) - ev(t, nbio.tick(), os.ERROR_NONE) + ev(t, nbio.tick(), nil) nbio.connect_poly(ep, t, proc(t: ^testing.T, socket: net.TCP_Socket, err: net.Network_Error) { ev(t, err, nil) - nbio.close_poly(socket, t, proc(t: ^testing.T, ok: bool) { - ev(t, ok, true) + nbio.close_poly(socket, t, proc(t: ^testing.T, err: nbio.FS_Error) { + ev(t, err, nil) }) }) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) } @(test) close_errors_send :: proc(t: ^testing.T) { server, ep := open_next_available_local_port(t) - nbio.accept_poly(server, t, proc(t: ^testing.T, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + nbio.accept_poly(server, t, proc(t: ^testing.T, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ev(t, err, nil) bytes := make([]byte, mem.Megabyte * 100, context.temp_allocator) - nbio.send_all_tcp_poly(client, bytes, t, proc(t: ^testing.T, sent: int, err: net.Network_Error) { + nbio.send_all_tcp_poly(client, bytes, t, proc(t: ^testing.T, sent: int, err: net.TCP_Send_Error) { ev(t, sent < mem.Megabyte * 100, true) ev(t, err, net.TCP_Send_Error.Connection_Closed) }) }) - ev(t, nbio.tick(), os.ERROR_NONE) + ev(t, nbio.tick(), nil) nbio.connect_poly(ep, t, proc(t: ^testing.T, socket: net.TCP_Socket, err: net.Network_Error) { ev(t, err, nil) - nbio.close_poly(socket, t, proc(t: ^testing.T, ok: bool) { - ev(t, ok, true) + nbio.close_poly(socket, t, proc(t: ^testing.T, err: nbio.FS_Error) { + ev(t, err, nil) }) }) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) } @(test) usage_across_threads :: proc(t: ^testing.T) { testing.set_fail_timeout(t, time.Second * 10) - handle: os.Handle + handle: nbio.Handle thread_done: sync.One_Shot_Event - open_thread := thread.create_and_start_with_poly_data3(t, &handle, &thread_done, proc(t: ^testing.T, handle: ^os.Handle, thread_done: ^sync.One_Shot_Event) { + open_thread := thread.create_and_start_with_poly_data3(t, &handle, &thread_done, proc(t: ^testing.T, handle: ^nbio.Handle, thread_done: ^sync.One_Shot_Event) { fd, errno := nbio.open(#file) - ev(t, errno, os.ERROR_NONE) + ev(t, errno, nil) handle^ = fd @@ -242,8 +242,8 @@ usage_across_threads :: proc(t: ^testing.T) { thread.destroy(open_thread) buf: [128]byte - nbio.read_at_poly(handle, 0, buf[:], t, proc(t: ^testing.T, read: int, errno: os.Errno) { - ev(t, errno, os.ERROR_NONE) + nbio.read_at_poly(handle, 0, buf[:], t, proc(t: ^testing.T, read: int, errno: nbio.FS_Error) { + ev(t, errno, nil) e(t, read > 0) }) diff --git a/tests/core/nbio/poly.odin b/tests/core/nbio/poly.odin index b12ea506c8a..8c2d633db62 100644 --- a/tests/core/nbio/poly.odin +++ b/tests/core/nbio/poly.odin @@ -31,32 +31,32 @@ all_poly_work :: proc(tt: ^testing.T) { ev(t, three, 3) }) - nbio.close_poly(os.INVALID_HANDLE, 1, proc(one: int, ok: bool) { + nbio.close_poly(nbio.Handle(os.INVALID_HANDLE), 1, proc(one: int, err: nbio.FS_Error) { ev(t, one, 1) - ev(t, ok, false) + e(t, err != nil) }) - nbio.close_poly2(os.INVALID_HANDLE, 1, 2, proc(one: int, two: int, ok: bool) { + nbio.close_poly2(nbio.Handle(os.INVALID_HANDLE), 1, 2, proc(one: int, two: int, err: nbio.FS_Error) { ev(t, one, 1) ev(t, two, 2) - ev(t, ok, false) + e(t, err != nil) }) - nbio.close_poly3(os.INVALID_HANDLE, 1, 2, 3, proc(one: int, two: int, three: int, ok: bool) { + nbio.close_poly3(nbio.Handle(os.INVALID_HANDLE), 1, 2, 3, proc(one: int, two: int, three: int, err: nbio.FS_Error) { ev(t, one, 1) ev(t, two, 2) ev(t, three, 3) - ev(t, ok, false) + e(t, err != nil) }) - nbio.accept_poly(0, 1, proc(one: int, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + nbio.accept_poly(0, 1, proc(one: int, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ev(t, one, 1) e(t, err != nil) }) - nbio.accept_poly2(0, 1, 2, proc(one: int, two: int, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + nbio.accept_poly2(0, 1, 2, proc(one: int, two: int, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ev(t, one, 1) ev(t, two, 2) e(t, err != nil) }) - nbio.accept_poly3(0, 1, 2, 3, proc(one: int, two: int, three: int, client: net.TCP_Socket, source: net.Endpoint, err: net.Network_Error) { + nbio.accept_poly3(0, 1, 2, 3, proc(one: int, two: int, three: int, client: net.TCP_Socket, source: net.Endpoint, err: net.Accept_Error) { ev(t, one, 1) ev(t, two, 2) ev(t, three, 3) @@ -79,100 +79,137 @@ all_poly_work :: proc(tt: ^testing.T) { nbio.close(socket) }) - on_recv1 :: proc(one: int, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error) { + on_recv_tcp1 :: proc(one: int, received: int, err: net.TCP_Recv_Error) { + ev(t, one, 1) + } + on_recv_tcp2 :: proc(one: int, two: int, received: int, err: net.TCP_Recv_Error) { + ev(t, one, 1) + ev(t, two, 2) + } + on_recv_tcp3 :: proc(one: int, two: int, three: int, received: int, err: net.TCP_Recv_Error) { + ev(t, one, 1) + ev(t, two, 2) + ev(t, three, 3) + } + + nbio.recv_tcp_poly (0, nil, 1, on_recv_tcp1) + nbio.recv_tcp_poly2(0, nil, 1, 2, on_recv_tcp2) + nbio.recv_tcp_poly3(0, nil, 1, 2, 3, on_recv_tcp3) + + nbio.recv_all_tcp_poly (0, nil, 1, on_recv_tcp1) + nbio.recv_all_tcp_poly2(0, nil, 1, 2, on_recv_tcp2) + nbio.recv_all_tcp_poly3(0, nil, 1, 2, 3, on_recv_tcp3) + + on_recv_udp1 :: proc(one: int, received: int, client: net.Endpoint, err: net.UDP_Recv_Error) { ev(t, one, 1) } - on_recv2 :: proc(one: int, two: int, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error) { + on_recv_udp2 :: proc(one: int, two: int, received: int, client: net.Endpoint, err: net.UDP_Recv_Error) { ev(t, one, 1) ev(t, two, 2) } - on_recv3 :: proc(one: int, two: int, three: int, received: int, udp_client: Maybe(net.Endpoint), err: net.Network_Error) { + on_recv_udp3 :: proc(one: int, two: int, three: int, received: int, client: net.Endpoint, err: net.UDP_Recv_Error) { ev(t, one, 1) ev(t, two, 2) ev(t, three, 3) } - nbio.recv_poly (net.TCP_Socket(0), nil, 1, on_recv1) - nbio.recv_poly2(net.TCP_Socket(0), nil, 1, 2, on_recv2) - nbio.recv_poly3(net.TCP_Socket(0), nil, 1, 2, 3, on_recv3) + nbio.recv_udp_poly (0, nil, 1, on_recv_udp1) + nbio.recv_udp_poly2(0, nil, 1, 2, on_recv_udp2) + nbio.recv_udp_poly3(0, nil, 1, 2, 3, on_recv_udp3) + + nbio.recv_all_udp_poly (0, nil, 1, on_recv_udp1) + nbio.recv_all_udp_poly2(0, nil, 1, 2, on_recv_udp2) + nbio.recv_all_udp_poly3(0, nil, 1, 2, 3, on_recv_udp3) - nbio.recv_all_poly (net.TCP_Socket(0), nil, 1, on_recv1) - nbio.recv_all_poly2(net.TCP_Socket(0), nil, 1, 2, on_recv2) - nbio.recv_all_poly3(net.TCP_Socket(0), nil, 1, 2, 3, on_recv3) + on_send_tcp1 :: proc(one: int, sent: int, err: net.TCP_Send_Error) { + ev(t, one, 1) + e(t, err != nil) + } + on_send_tcp2 :: proc(one: int, two: int, sent: int, err: net.TCP_Send_Error) { + ev(t, one, 1) + ev(t, two, 2) + e(t, err != nil) + } + on_send_tcp3 :: proc(one: int, two: int, three: int, sent: int, err: net.TCP_Send_Error) { + ev(t, one, 1) + ev(t, two, 2) + ev(t, three, 3) + e(t, err != nil) + } - on_send1 :: proc(one: int, sent: int, err: net.Network_Error) { + on_send_udp1 :: proc(one: int, sent: int, err: net.UDP_Send_Error) { ev(t, one, 1) e(t, err != nil) } - on_send2 :: proc(one: int, two: int, sent: int, err: net.Network_Error) { + on_send_udp2 :: proc(one: int, two: int, sent: int, err: net.UDP_Send_Error) { ev(t, one, 1) ev(t, two, 2) e(t, err != nil) } - on_send3 :: proc(one: int, two: int, three: int, sent: int, err: net.Network_Error) { + on_send_udp3 :: proc(one: int, two: int, three: int, sent: int, err: net.UDP_Send_Error) { ev(t, one, 1) ev(t, two, 2) ev(t, three, 3) e(t, err != nil) } - nbio.send_tcp_poly (0, nil, 1, on_send1) - nbio.send_tcp_poly2(0, nil, 1, 2, on_send2) - nbio.send_tcp_poly3(0, nil, 1, 2, 3, on_send3) + nbio.send_tcp_poly (0, nil, 1, on_send_tcp1) + nbio.send_tcp_poly2(0, nil, 1, 2, on_send_tcp2) + nbio.send_tcp_poly3(0, nil, 1, 2, 3, on_send_tcp3) - nbio.send_udp_poly (net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, on_send1) - nbio.send_udp_poly2(net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, 2, on_send2) - nbio.send_udp_poly3(net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, 2, 3, on_send3) + nbio.send_udp_poly (net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, on_send_udp1) + nbio.send_udp_poly2(net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, 2, on_send_udp2) + nbio.send_udp_poly3(net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, 2, 3, on_send_udp3) - nbio.send_all_tcp_poly (0, nil, 1, on_send1) - nbio.send_all_tcp_poly2(0, nil, 1, 2, on_send2) - nbio.send_all_tcp_poly3(0, nil, 1, 2, 3, on_send3) + nbio.send_all_tcp_poly (0, nil, 1, on_send_tcp1) + nbio.send_all_tcp_poly2(0, nil, 1, 2, on_send_tcp2) + nbio.send_all_tcp_poly3(0, nil, 1, 2, 3, on_send_tcp3) - nbio.send_all_udp_poly (net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, on_send1) - nbio.send_all_udp_poly2(net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, 2, on_send2) - nbio.send_all_udp_poly3(net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, 2, 3, on_send3) + nbio.send_all_udp_poly (net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, on_send_udp1) + nbio.send_all_udp_poly2(net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, 2, on_send_udp2) + nbio.send_all_udp_poly3(net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 80}, 0, nil, 1, 2, 3, on_send_udp3) - on_read1 :: proc(one: int, read: int, err: os.Errno) { + on_read1 :: proc(one: int, read: int, err: nbio.FS_Error) { ev(t, one, 1) } - on_read2 :: proc(one: int, two: int, read: int, err: os.Errno) { + on_read2 :: proc(one: int, two: int, read: int, err: nbio.FS_Error) { ev(t, one, 1) ev(t, two, 2) } - on_read3 :: proc(one: int, two: int, three: int, read: int, err: os.Errno) { + on_read3 :: proc(one: int, two: int, three: int, read: int, err: nbio.FS_Error) { ev(t, one, 1) ev(t, two, 2) ev(t, three, 3) } - nbio.read_at_poly (os.INVALID_HANDLE, 0, nil, 1, on_read1) - nbio.read_at_poly2(os.INVALID_HANDLE, 0, nil, 1, 2, on_read2) - nbio.read_at_poly3(os.INVALID_HANDLE, 0, nil, 1, 2, 3, on_read3) + nbio.read_at_poly (nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, on_read1) + nbio.read_at_poly2(nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, 2, on_read2) + nbio.read_at_poly3(nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, 2, 3, on_read3) - nbio.read_at_all_poly (os.INVALID_HANDLE, 0, nil, 1, on_read1) - nbio.read_at_all_poly2(os.INVALID_HANDLE, 0, nil, 1, 2, on_read2) - nbio.read_at_all_poly3(os.INVALID_HANDLE, 0, nil, 1, 2, 3, on_read3) + nbio.read_at_all_poly (nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, on_read1) + nbio.read_at_all_poly2(nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, 2, on_read2) + nbio.read_at_all_poly3(nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, 2, 3, on_read3) - on_write1 :: proc(one: int, written: int, err: os.Errno) { + on_write1 :: proc(one: int, written: int, err: nbio.FS_Error) { ev(t, one, 1) } - on_write2 :: proc(one: int, two: int, written: int, err: os.Errno) { + on_write2 :: proc(one: int, two: int, written: int, err: nbio.FS_Error) { ev(t, one, 1) ev(t, two, 2) } - on_write3 :: proc(one: int, two: int, three: int, written: int, err: os.Errno) { + on_write3 :: proc(one: int, two: int, three: int, written: int, err: nbio.FS_Error) { ev(t, one, 1) ev(t, two, 2) ev(t, three, 3) } - nbio.write_at_poly (os.INVALID_HANDLE, 0, nil, 1, on_write1) - nbio.write_at_poly2(os.INVALID_HANDLE, 0, nil, 1, 2, on_write2) - nbio.write_at_poly3(os.INVALID_HANDLE, 0, nil, 1, 2, 3, on_write3) + nbio.write_at_poly (nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, on_write1) + nbio.write_at_poly2(nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, 2, on_write2) + nbio.write_at_poly3(nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, 2, 3, on_write3) - nbio.write_at_all_poly (os.INVALID_HANDLE, 0, nil, 1, on_write1) - nbio.write_at_all_poly2(os.INVALID_HANDLE, 0, nil, 1, 2, on_write2) - nbio.write_at_all_poly3(os.INVALID_HANDLE, 0, nil, 1, 2, 3, on_write3) + nbio.write_at_all_poly (nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, on_write1) + nbio.write_at_all_poly2(nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, 2, on_write2) + nbio.write_at_all_poly3(nbio.Handle(os.INVALID_HANDLE), 0, nil, 1, 2, 3, on_write3) nbio.next_tick_poly(1, proc(one: int) { ev(t, one, 1) @@ -187,20 +224,20 @@ all_poly_work :: proc(tt: ^testing.T) { ev(t, three, 3) }) - nbio.poll_poly(os.INVALID_HANDLE, .Read, false, 1, proc(one: int, event: nbio.Poll_Event) { + nbio.poll_poly(nbio.Handle(os.INVALID_HANDLE), .Read, false, 1, proc(one: int, event: nbio.Poll_Event) { ev(t, one, 1) }) - nbio.poll_poly2(os.INVALID_HANDLE, .Read, false, 1, 2, proc(one: int, two: int, event: nbio.Poll_Event) { + nbio.poll_poly2(nbio.Handle(os.INVALID_HANDLE), .Read, false, 1, 2, proc(one: int, two: int, event: nbio.Poll_Event) { ev(t, one, 1) ev(t, two, 2) }) - nbio.poll_poly3(os.INVALID_HANDLE, .Read, false, 1, 2, 3, proc(one: int, two: int, three: int, event: nbio.Poll_Event) { + nbio.poll_poly3(nbio.Handle(os.INVALID_HANDLE), .Read, false, 1, 2, 3, proc(one: int, two: int, three: int, event: nbio.Poll_Event) { ev(t, one, 1) ev(t, two, 2) ev(t, three, 3) }) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) } @(test) @@ -209,35 +246,35 @@ read_entire_file_works :: proc(tt: ^testing.T) { t = tt fd, errno := nbio.open(#file) - ev(t, errno, os.ERROR_NONE) + ev(t, errno, nil) - nbio.read_entire_file(fd, 1, proc(one: int, buf: []byte, err: os.Errno) { + nbio.read_entire_file(fd, 1, proc(one: int, buf: []byte, err: nbio.FS_Error) { ev(t, one, 1) - ev(t, err, os.ERROR_NONE) + ev(t, err, nil) ev(t, string(buf), #load(#file, string)) delete(buf) }) - nbio.read_entire_file2(fd, 1, 2, proc(one: int, two: int, buf: []byte, err: os.Errno) { + nbio.read_entire_file2(fd, 1, 2, proc(one: int, two: int, buf: []byte, err: nbio.FS_Error) { ev(t, one, 1) ev(t, two, 2) - ev(t, err, os.ERROR_NONE) + ev(t, err, nil) ev(t, string(buf), #load(#file, string)) delete(buf) }) - nbio.read_entire_file3(fd, 1, 2, 3, proc(one: int, two: int, three: int, buf: []byte, err: os.Errno) { + nbio.read_entire_file3(fd, 1, 2, 3, proc(one: int, two: int, three: int, buf: []byte, err: nbio.FS_Error) { ev(t, one, 1) ev(t, two, 2) ev(t, three, 3) - ev(t, err, os.ERROR_NONE) + ev(t, err, nil) ev(t, string(buf), #load(#file, string)) delete(buf) }) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) nbio.close(fd) - ev(t, nbio.run(), os.ERROR_NONE) + ev(t, nbio.run(), nil) }