Files
Odin/core/nbio/impl_others.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() {
}