mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-26 00:03:54 +00:00
219 lines
4.4 KiB
Odin
219 lines
4.4 KiB
Odin
#+build !darwin
|
|
#+build !freebsd
|
|
#+build !openbsd
|
|
#+build !netbsd
|
|
#+build !linux
|
|
#+build !windows
|
|
#+private
|
|
package nbio
|
|
|
|
import "core:container/avl"
|
|
import "core:container/pool"
|
|
import "core:container/queue"
|
|
import "core:mem"
|
|
import "core:slice"
|
|
import "core:time"
|
|
|
|
_FULLY_SUPPORTED :: false
|
|
|
|
_Event_Loop :: struct {
|
|
completed: queue.Queue(^Operation),
|
|
timeouts: avl.Tree(^Operation),
|
|
}
|
|
|
|
_Handle :: uintptr
|
|
|
|
_CWD :: Handle(-100)
|
|
|
|
MAX_RW :: mem.Gigabyte
|
|
|
|
_Operation :: struct {
|
|
removed: bool,
|
|
}
|
|
|
|
_Accept :: struct {}
|
|
|
|
_Close :: struct {}
|
|
|
|
_Dial :: struct {}
|
|
|
|
_Recv :: struct {
|
|
small_bufs: [1][]byte,
|
|
}
|
|
|
|
_Send :: struct {
|
|
small_bufs: [1][]byte,
|
|
}
|
|
|
|
_Read :: struct {}
|
|
|
|
_Write :: struct {}
|
|
|
|
_Timeout :: struct {
|
|
expires: time.Time,
|
|
}
|
|
|
|
_Poll :: struct {}
|
|
|
|
_Send_File :: struct {}
|
|
|
|
_Open :: struct {}
|
|
|
|
_Stat :: struct {}
|
|
|
|
_Splice :: struct {}
|
|
|
|
_Remove :: struct {}
|
|
|
|
_Link_Timeout :: struct {}
|
|
|
|
_init :: proc(l: ^Event_Loop, allocator: mem.Allocator) -> (rerr: General_Error) {
|
|
l.completed.data.allocator = allocator
|
|
|
|
avl.init_cmp(&l.timeouts, timeouts_cmp, allocator)
|
|
|
|
return nil
|
|
|
|
timeouts_cmp :: #force_inline proc(a, b: ^Operation) -> slice.Ordering {
|
|
switch {
|
|
case a.timeout._impl.expires._nsec < b.timeout._impl.expires._nsec:
|
|
return .Less
|
|
case a.timeout._impl.expires._nsec > b.timeout._impl.expires._nsec:
|
|
return .Greater
|
|
case uintptr(a) < uintptr(b):
|
|
return .Less
|
|
case uintptr(a) > uintptr(b):
|
|
return .Greater
|
|
case:
|
|
assert(a == b)
|
|
return .Equal
|
|
}
|
|
}
|
|
}
|
|
|
|
_destroy :: proc(l: ^Event_Loop) {
|
|
queue.destroy(&l.completed)
|
|
avl.destroy(&l.timeouts, false)
|
|
}
|
|
|
|
__tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> General_Error {
|
|
l.now = time.now()
|
|
|
|
for op in queue.pop_front_safe(&l.completed) {
|
|
if !op._impl.removed {
|
|
op.cb(op)
|
|
}
|
|
if !op.detached {
|
|
pool.put(&l.operation_pool, op)
|
|
}
|
|
}
|
|
|
|
iter := avl.iterator(&l.timeouts, .Forward)
|
|
for node in avl.iterator_next(&iter) {
|
|
op := node.value
|
|
cexpires := time.diff(l.now, op.timeout._impl.expires)
|
|
|
|
done := cexpires <= 0
|
|
if done {
|
|
op.cb(op)
|
|
avl.remove_node(&l.timeouts, node)
|
|
if !op.detached {
|
|
pool.put(&l.operation_pool, op)
|
|
}
|
|
continue
|
|
}
|
|
|
|
break
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
_create_socket :: proc(l: ^Event_Loop, family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) {
|
|
return nil, .Network_Unreachable
|
|
}
|
|
|
|
_listen :: proc(socket: TCP_Socket, backlog := 1000) -> Listen_Error {
|
|
return .Network_Unreachable
|
|
}
|
|
|
|
_exec :: proc(op: ^Operation) {
|
|
switch op.type {
|
|
case .Timeout:
|
|
_, _, err := avl.find_or_insert(&op.l.timeouts, op)
|
|
if err != nil {
|
|
panic("nbio: allocation failure")
|
|
}
|
|
return
|
|
case .Accept:
|
|
op.accept.err = .Network_Unreachable
|
|
case .Close:
|
|
op.close.err = .Unsupported
|
|
case .Dial:
|
|
op.dial.err = Dial_Error.Network_Unreachable
|
|
case .Recv:
|
|
switch _ in op.recv.socket {
|
|
case TCP_Socket: op.recv.err = TCP_Recv_Error.Network_Unreachable
|
|
case UDP_Socket: op.recv.err = UDP_Recv_Error.Network_Unreachable
|
|
case: op.recv.err = TCP_Recv_Error.Network_Unreachable
|
|
}
|
|
case .Send:
|
|
switch _ in op.send.socket {
|
|
case TCP_Socket: op.send.err = TCP_Send_Error.Network_Unreachable
|
|
case UDP_Socket: op.send.err = UDP_Send_Error.Network_Unreachable
|
|
case: op.send.err = TCP_Send_Error.Network_Unreachable
|
|
}
|
|
case .Send_File:
|
|
op.sendfile.err = .Network_Unreachable
|
|
case .Read:
|
|
op.read.err = .Unsupported
|
|
case .Write:
|
|
op.write.err = .Unsupported
|
|
case .Poll:
|
|
op.poll.result = .Error
|
|
case .Open:
|
|
op.open.err = .Unsupported
|
|
case .Stat:
|
|
op.stat.err = .Unsupported
|
|
case .None, ._Link_Timeout, ._Remove, ._Splice:
|
|
fallthrough
|
|
case:
|
|
unreachable()
|
|
}
|
|
|
|
_, err := queue.push_back(&op.l.completed, op)
|
|
if err != nil {
|
|
panic("nbio: allocation failure")
|
|
}
|
|
}
|
|
|
|
_remove :: proc(target: ^Operation) {
|
|
#partial switch target.type {
|
|
case .Timeout:
|
|
avl.remove_value(&target.l.timeouts, target)
|
|
if !target.detached {
|
|
pool.put(&target.l.operation_pool, target)
|
|
}
|
|
case:
|
|
target._impl.removed = true
|
|
}
|
|
}
|
|
|
|
_open_sync :: proc(l: ^Event_Loop, path: string, dir: Handle, mode: File_Flags, perm: Permissions) -> (handle: Handle, err: FS_Error) {
|
|
return 0, FS_Error.Unsupported
|
|
}
|
|
|
|
_associate_handle :: proc(handle: uintptr, l: ^Event_Loop) -> (Handle, Association_Error) {
|
|
return Handle(handle), nil
|
|
}
|
|
|
|
_associate_socket :: proc(socket: Any_Socket, l: ^Event_Loop) -> Association_Error {
|
|
return nil
|
|
}
|
|
|
|
_wake_up :: proc(l: ^Event_Loop) {
|
|
}
|
|
|
|
_yield :: proc() {
|
|
}
|