package core:nbio

⌘K
Ctrl+K
or
/

    Overview

    package nbio implements a non-blocking I/O and event loop abstraction layer over several platform-specific asynchronous I/O APIs.

    More examples can be found in Odin's examples repository at examples/nbio.

    Event Loop:

    Each thread may have at most one event loop associated with it. This is enforced by the package, as running multiple event loops on a single thread does not make sense.

    Event loops are reference counted and managed by the package.

    acquire_thread_event_loop and release_thread_event_loop can be used to acquire and release a reference. Acquiring must be done before any operation is done.

    The event loop progresses in ticks. A tick checks if any work is to be done, and based on the given timeout may block waiting for work.

    Ticks are typically done using the tick, run, and run_until procedures.

    Example:
    package main
    
    import "core:nbio"
    import "core:time"
    import "core:fmt"
    
    main :: proc() {
    	err := nbio.acquire_thread_event_loop()
    	assert(err == nil)
    	defer nbio.release_thread_event_loop()
    
    	nbio.timeout(time.Second, proc(_: ^nbio.Operation) {
    		fmt.println("Hellope after 1 second!")
    	})
    
    	err = nbio.run()
    	assert(err == nil)
    }
    

    Time and timeouts:

    Timeouts are intentionally slightly inaccurate by design.

    A timeout is not checked continuously, instead, it is evaluated only when a tick occurs. This means if a tick took a long time, your timeout may be ready for a bit of time already before the callback is called.

    The function now returns the current time as perceived by the event loop. This value is cached at least once per tick so it is fast to retrieve.

    Most operations also take an optional timeout when executed. If the timeout completes before the operation, the operation is cancelled and called back with a .Timeout error.

    Threading:

    The package has a concept of I/O threads (threads that are ticking) and worker threads (any other thread).

    An I/O thread is mostly self contained, operations are executed on it, and callbacks run on it.

    If you try to execute an operation on a thread that has no running event loop a panic will be executed. Instead a worker thread can execute operations onto a running event loop by taking it's reference and executing operations with that reference.

    In this case: The operation is enqueued from the worker thread The I/O thread is optionally woken up from blocking for work with wake_up The next tick, the operation is executed by the I/O thread The callback is invoked on the I/O thread

    Example:
    package main
    
    import "core:nbio"
    import "core:net"
    import "core:thread"
    import "core:time"
    
    Connection :: struct {
    	loop:   ^nbio.Event_Loop,
    	socket: net.TCP_Socket,
    }
    
    main :: proc() {
    	workers: thread.Pool
    	thread.pool_init(&workers, context.allocator, 2)
    	thread.pool_start(&workers)
    
    	err := nbio.acquire_thread_event_loop()
    	defer nbio.release_thread_event_loop()
    	assert(err == nil)
    
    	server, listen_err := nbio.listen_tcp({nbio.IP4_Any, 1234})
    	assert(listen_err == nil)
    	nbio.accept_poly(server, &workers, on_accept)
    
    	err = nbio.run()
    	assert(err == nil)
    
    	on_accept :: proc(op: ^nbio.Operation, workers: ^thread.Pool) {
    		assert(op.accept.err == nil)
    
    		nbio.accept_poly(op.accept.socket, workers, on_accept)
    
    		thread.pool_add_task(workers, context.allocator, do_work, new_clone(Connection{
    			loop   = op.l,
    			socket = op.accept.client,
    		}))
    	}
    
    	do_work :: proc(t: thread.Task) {
    		connection := (^Connection)(t.data)
    
    		// Imagine CPU intensive work that's been ofloaded to a worker thread.
    		time.sleep(time.Second * 1)
    
    		nbio.send_poly(connection.socket, {transmute([]byte)string("Hellope!\n")}, connection, on_sent, l=connection.loop)
    	}
    
    	on_sent :: proc(op: ^nbio.Operation, connection: ^Connection) {
    		assert(op.send.err == nil)
    		// Client got our message, clean up.
    		nbio.close(connection.socket)
    		free(connection)
    	}
    }
    

    Handle and socket association:

    Most platforms require handles (files, sockets, etc.) to be explicitly associated with an event loop or configured for non-blocking/asynchronous operation.

    On some platforms (notably Windows), this requires a specific flag at open time (.Non_Blocking for core:os) and association may fail if the handle was not created correctly.

    For this reason, prefer open and create_socket from this package instead.

    associate_handle, associate_file, and associate_socket can be used for externally opened files/sockets.

    Offsets and positional I/O:

    Operations do not implicitly use or modify a handle’s internal file offset.

    Instead, operations such as read and write are positional and require an explicit offset.

    This avoids ambiguity and subtle bugs when multiple asynchronous operations are issued concurrently against the same handle.

    Contexts and callbacks:

    The context inside a callback is not the context that submitted the operation.

    Instead, the callback receives the context that was active when the event loop function (tick, run, etc.) was called.

    This is because otherwise the context would have to be copied and held onto for each operation.

    If the submitting context is required inside the callback, it must be copied into the operation’s user data explicitly.

    Example:
    nbio.timeout_poly(time.Second, new_clone(context), proc(_: ^Operation, ctx: ^runtime.Context) {
    	context = ctx^
    	free(ctx)
    })
    

    Callback scheduling guarantees:

    Callbacks are guaranteed to be invoked in a later tick, never synchronously. This means that the operation returned from a procedure is at least valid till the end of the current tick, because an operation is freed after it's callback is called. Thus you can set user data after an execution is queued, or call remove, removing subtle "race" conditions and simplifying control flow.

    Index

    Variables (0)

    This section is empty.

    Procedures (90)
    Procedure Groups (0)

    This section is empty.

    Types

    Accept ¶

    Accept :: struct {
    	// Socket to accept an incoming connection on.
    	socket:          net.TCP_Socket,
    	// When this operation expires and should be timed out.
    	expires:         time.Time,
    	// The connection that was accepted.
    	client:          net.TCP_Socket,
    	// The connection's remote origin.
    	client_endpoint: net.Endpoint,
    	// An error, if it occurred.
    	err:             net.Accept_Error,
    	// Implementation specifics, private.
    	_impl:           _Accept `fmt:"-"`,
    }

    Accept_Error ¶

    Accept_Error :: net.Accept_Error

    Address ¶

    Address :: net.Address

    Address_Family ¶

    Address_Family :: net.Address_Family
    Related Procedures With Parameters

    Association_Error ¶

    Association_Error :: enum int {
    	None, 
    	// The given file/handle/socket was not opened in a mode that it can be made non-blocking afterwards.
    	// 
    	// On Windows, this can happen when a file is not opened with the `FILE_FLAG_OVERLAPPED` flag.
    	// If using `core:os`, that is set when you specify the `O_NONBLOCK` flag.
    	// There is no way to add that after the fact.
    	Not_Possible_To_Associate, 
    	// The given handle is not a valid handle.
    	Invalid_Handle, 
    	// No network connection, or the network stack is not initialized.
    	Network_Unreachable, 
    }
    Related Procedures With Returns

    Closable ¶

    Closable :: union {
    	net.TCP_Socket, 
    	net.UDP_Socket, 
    	_Handle, 
    }
     

    A union of closable types that can be passed to close.

    Related Procedures With Parameters

    Close ¶

    Close :: struct {
    	// The subject to close.
    	subject: Closable,
    	// An error, if it occurred.
    	err:     FS_Error,
    	// Implementation specifics, private.
    	_impl:   _Close `fmt:"-"`,
    }

    Create_Socket_Error ¶

    Create_Socket_Error :: net.Create_Socket_Error
    Related Procedures With Returns

    Dial ¶

    Dial :: struct {
    	// The endpoint to connect to.
    	endpoint: net.Endpoint,
    	// When this operation expires and should be timed out.
    	expires:  time.Time,
    	// Errors that can be returned: `Create_Socket_Error`, or `Dial_Error`.
    	err:      net.Network_Error,
    	// The socket to communicate with the connected server.
    	socket:   net.TCP_Socket,
    	// Implementation specifics, private.
    	_impl:    _Dial `fmt:"-"`,
    }

    Dial_Error ¶

    Dial_Error :: net.Dial_Error

    FS_Error ¶

    FS_Error :: enum i32 {
    	None, 
    	Unsupported       = 50, 
    	Allocation_Failed = 14, 
    	Timeout           = 258, 
    	Invalid_Argument  = 160, 
    	Permission_Denied = 5, 
    	EOF               = 38, 
    	Exists            = 80, 
    	Not_Found         = 2, 
    }
     

    Errors gotten from file system operations.

    Related Procedures With Returns

    File_Flag ¶

    File_Flag :: enum int {
    	// Open for reading.
    	Read, 
    	// Open for writing.
    	Write, 
    	// Append writes to the end of the file.
    	Append, 
    	// Create the file if it does not exist.
    	Create, 
    	// Fail if the file already exists (used with Create).
    	Excl, 
    	Sync, 
    	// Truncate the file on open.
    	Trunc, 
    }

    File_Flags ¶

    File_Flags :: bit_set[File_Flag; int]
    Related Procedures With Parameters

    File_Type ¶

    File_Type :: enum int {
    	// File type could not be determined.
    	Undetermined, 
    	// Regular file.
    	Regular, 
    	// Directory.
    	Directory, 
    	// Symbolic link.
    	Symlink, 
    	// Pipe or socket.
    	Pipe_Or_Socket, 
    	// Character or block device.
    	Device, 
    }

    General_Error ¶

    General_Error :: enum i32 {
    	None, 
    	Allocation_Failed = 14, 
    	Unsupported       = 50, 
    }
     

    Errors regarding general usage of the event loop.

    Related Procedures With Returns

    IP4_Address ¶

    IP4_Address :: net.IP4_Address
    Related Constants

    IP6_Address ¶

    IP6_Address :: net.IP6_Address
    Related Constants

    Listen_Error ¶

    Listen_Error :: net.Listen_Error

    Network_Error ¶

    Network_Error :: net.Network_Error
    Related Procedures With Returns

    Open ¶

    Open :: struct {
    	// Base directory the path is relative to.
    	dir:    _Handle,
    	// Path to the file.
    	path:   string,
    	// File open mode flags.
    	mode:   bit_set[File_Flag; int],
    	// Permissions used if the file is created.
    	perm:   Permissions,
    	// The opened file handle.
    	handle: _Handle,
    	// An error, if it occurred.
    	err:    FS_Error,
    	// Implementation specifics, private.
    	_impl:  _Open `fmt:"-"`,
    }

    Operation_Type ¶

    Operation_Type :: enum i32 {
    	None, 
    	Accept, 
    	Close, 
    	Dial, 
    	Read, 
    	Recv, 
    	Send, 
    	Write, 
    	Timeout, 
    	Poll, 
    	Send_File, 
    	Open, 
    	Stat, 
    	_Link_Timeout, 
    	_Remove, 
    	_Splice, 
    }

    Permission_Flag ¶

    Permission_Flag :: enum u32 {
    	Execute_Other = 0, 
    	Write_Other   = 1, 
    	Read_Other    = 2, 
    	Execute_Group = 3, 
    	Write_Group   = 4, 
    	Read_Group    = 5, 
    	Execute_User  = 6, 
    	Write_User    = 7, 
    	Read_User     = 8, 
    }

    Permissions ¶

    Permissions :: distinct bit_set[Permission_Flag; u32]
     

    File permission bit-set.

    This type represents POSIX-style file permissions, split into user, group, and other categories, each with read, write, and execute flags.

    Related Procedures With Parameters
    Related Constants

    Platform_Error ¶

    Platform_Error :: sys_windows.System_Error

    Poll ¶

    Poll :: struct {
    	// Socket to poll.
    	socket:  net.Any_Socket,
    	// Event to poll for.
    	event:   Poll_Event,
    	// When this operation expires and should be timed out.
    	expires: time.Time,
    	// Result of the poll.
    	result:  Poll_Result,
    	// Implementation specifics, private.
    	_impl:   _Poll `fmt:"-"`,
    }

    Poll_Event ¶

    Poll_Event :: enum int {
    	// The subject is ready to be received from.
    	Receive, 
    	// The subject is ready to be sent to.
    	Send, 
    }
    Related Procedures With Parameters

    Poll_Result ¶

    Poll_Result :: enum i32 {
    	// The requested event is ready.
    	Ready, 
    	// The operation timed out before the event became ready.
    	Timeout, 
    	// The socket was invalid.
    	Invalid_Argument, 
    	// An unspecified error occurred.
    	Error, 
    }

    Read ¶

    Read :: struct {
    	// Handle to read from.
    	handle:  _Handle,
    	// Buffer to read data into.
    	buf:     []u8 `fmt:"v,read"`,
    	// Offset to read from.
    	offset:  int,
    	// Whether to read until the buffer is full or an error occurs.
    	all:     bool,
    	// When this operation expires and should be timed out.
    	expires: time.Time,
    	// Error, if it occurred.
    	err:     FS_Error,
    	// Number of bytes read.
    	read:    int,
    	// Implementation specifics, private.
    	_impl:   _Read `fmt:"-"`,
    }

    Read_Entire_File_Callback ¶

    Read_Entire_File_Callback :: proc(user_data: rawptr, data: []u8, err: Read_Entire_File_Error)
    Related Procedures With Parameters

    Read_Entire_File_Error ¶

    Read_Entire_File_Error :: struct {
    	operation: Operation_Type,
    	value:     FS_Error,
    }

    Recv ¶

    Recv :: struct {
    	// The socket to receive from.
    	socket:   net.Any_Socket,
    	// The buffers to receive data into.
    	// The outer slice is copied internally, but the backing arrays must remain alive.
    	// It is safe to access `bufs` during the callback.
    	bufs:     [][]u8,
    	// If true, the operation waits until all buffers are filled (TCP only).
    	all:      bool,
    	// When this operation expires and should be timed out.
    	expires:  time.Time,
    	// The source endpoint data was received from (UDP only).
    	source:   net.Endpoint,
    	// An error, if it occurred.
    	// If `received == 0` and `err == nil`, the connection was closed by the peer.
    	err:      net.Recv_Error,
    	// The number of bytes received.
    	received: int,
    	// Implementation specifics, private.
    	_impl:    _Recv `fmt:"-"`,
    }

    Recv_Error ¶

    Recv_Error :: net.Recv_Error
    Related Procedures With Parameters

    Send ¶

    Send :: struct {
    	// The socket to send to.
    	socket:   net.Any_Socket,
    	// The buffers to send.
    	// The outer slice is copied internally, but the backing arrays must remain alive.
    	bufs:     [][]u8 `fmt:"-"`,
    	// The destination endpoint to send to (UDP only).
    	endpoint: net.Endpoint,
    	// If true, the operation ensures all data is sent before completing.
    	all:      bool,
    	// When this operation expires and should be timed out.
    	expires:  time.Time,
    	// An error, if it occurred.
    	err:      net.Send_Error,
    	// The number of bytes sent.
    	sent:     int,
    	// Implementation specifics, private.
    	_impl:    _Send `fmt:"-"`,
    }

    Send_Error ¶

    Send_Error :: net.Send_Error
    Related Procedures With Parameters

    Send_File ¶

    Send_File :: struct {
    	// The TCP socket to send the file over.
    	socket:           net.TCP_Socket,
    	// The handle of the regular file to send.
    	file:             _Handle,
    	// When this operation expires and should be timed out.
    	expires:          time.Time,
    	// The starting offset within the file.
    	offset:           int,
    	// Number of bytes to send. If set to SEND_ENTIRE_FILE, the file size is retrieved 
    	// automatically and this field is updated to reflect the full size.
    	nbytes:           int,
    	// If true, the callback is triggered periodically as data is sent. 
    	// The callback will continue to be called until `sent == nbytes` or an error occurs.
    	progress_updates: bool,
    	// Total number of bytes (so far if `progress_updates` is true).
    	sent:             int,
    	// An error, if it occurred. Can be a filesystem or networking error.
    	err:              Send_File_Error,
    	// Implementation specifics, private.
    	_impl:            _Send_File `fmt:"-"`,
    }

    Send_File_Error ¶

    Send_File_Error :: union {
    	FS_Error, 
    	net.TCP_Send_Error, 
    }
    Related Procedures With Parameters

    Socket_Protocol ¶

    Socket_Protocol :: net.Socket_Protocol
    Related Procedures With Parameters

    Specifics ¶

    Specifics :: struct #raw_union {
    	accept:        Accept `raw_union_tag:"type=.Accept"`,
    	close:         Close `raw_union_tag:"type=.Close"`,
    	dial:          Dial `raw_union_tag:"type=.Dial"`,
    	read:          Read `raw_union_tag:"type=.Read"`,
    	recv:          Recv `raw_union_tag:"type=.Recv"`,
    	send:          Send `raw_union_tag:"type=.Send"`,
    	write:         Write `raw_union_tag:"type=.Write"`,
    	timeout:       Timeout `raw_union_tag:"type=.Timeout"`,
    	poll:          Poll `raw_union_tag:"type=.Poll"`,
    	sendfile:      Send_File `raw_union_tag:"type=.Send_File"`,
    	open:          Open `raw_union_tag:"type=.Open"`,
    	stat:          Stat `raw_union_tag:"type=.Stat"`,
    	_remove:       _Remove `raw_union_tag:"type=._Remove"`,
    	_link_timeout: _Link_Timeout `raw_union_tag:"type=._Link_Timeout"`,
    	_splice:       _Splice `raw_union_tag:"type=._Splice"`,
    }

    Stat ¶

    Stat :: struct {
    	// Handle to stat.
    	handle: _Handle,
    	// The type of the file.
    	type:   File_Type,
    	// Size of the file in bytes.
    	size:   i64 `fmt:"M"`,
    	// An error, if it occurred.
    	err:    FS_Error,
    	// Implementation specifics, private.
    	_impl:  _Stat `fmt:"-"`,
    }

    Timeout ¶

    Timeout :: struct {
    	// Duration after which the timeout expires.
    	duration: time.Duration,
    	// Implementation specifics, private.
    	_impl:    _Timeout `fmt:"-"`,
    }

    UDP_Socket ¶

    UDP_Socket :: net.UDP_Socket
    Related Procedures With Returns

    Write ¶

    Write :: struct {
    	// Handle to write to.
    	handle:  _Handle,
    	// Buffer containing data to write.
    	buf:     []u8,
    	// Offset to write to.
    	offset:  int,
    	// Whether to write until the buffer is fully written or an error occurs.
    	all:     bool,
    	// When this operation expires and should be timed out.
    	expires: time.Time,
    	// Error, if it occurred.
    	err:     FS_Error,
    	// Number of bytes written.
    	written: int,
    	// Implementation specifics, private.
    	_impl:   _Write `fmt:"-"`,
    }

    Constants

    CWD ¶

    CWD: _Handle : _CWD
     

    Sentinel handle representing the current/present working directory.

    FULLY_SUPPORTED ¶

    FULLY_SUPPORTED: bool : _FULLY_SUPPORTED
     

    If the package is fully supported on the current target. If it is not it will compile but work in a matter where things are unimplemented.

    Additionally if it is FULLY_SUPPORTED it may still return .Unsupported in acquire_thread_event_loop If the target does not support the needed syscalls for operating the package.

    IP4_Any ¶

    IP4_Any: net.IP4_Address : net.IP4_Any

    IP4_Loopback ¶

    IP4_Loopback: net.IP4_Address : net.IP4_Loopback

    IP6_Any ¶

    IP6_Any: net.IP6_Address : net.IP6_Any

    IP6_Loopback ¶

    IP6_Loopback: net.IP6_Address : net.IP6_Loopback

    MAX_USER_ARGUMENTS ¶

    MAX_USER_ARGUMENTS: int : #config(NBIO_MAX_USER_ARGUMENTS, 4)
     

    The maximum size of user arguments for an operation, can be increased at the cost of more RAM.

    NO_TIMEOUT ¶

    NO_TIMEOUT: time.Duration : -1

    Permissions_All ¶

    Permissions_All :: Permissions_Read_All + Permissions_Write_All + Permissions_Execute_All
     

    Read, write, and execute permissions for user, group, and others.

    Permissions_Default_Directory ¶

    Permissions_Default_Directory :: Permissions_Read_All + Permissions_Write_All + Permissions_Execute_All
     

    Default permissions used when creating a directory (read, write, and execute for everyone).

    Permissions_Default_File ¶

    Permissions_Default_File :: Permissions_Read_All + Permissions_Write_All
     

    Default permissions used when creating a file (read and write for everyone).

    Permissions_Execute_All ¶

    Permissions_Execute_All :: Permissions{.Execute_User, .Execute_Group, .Execute_Other}
     

    Convenience permission sets.

    Permissions_Read_All ¶

    Permissions_Read_All :: Permissions{.Read_User, .Read_Group, .Read_Other}

    Permissions_Read_Write_All ¶

    Permissions_Read_Write_All :: Permissions_Read_All + Permissions_Write_All
     

    Read and write permissions for user, group, and others.

    Permissions_Write_All ¶

    Permissions_Write_All :: Permissions{.Write_User, .Write_Group, .Write_Other}

    SEND_ENTIRE_FILE ¶

    SEND_ENTIRE_FILE: int : -1

    Variables

    This section is empty.

    Procedures

    accept ¶

    accept :: proc(socket: net.TCP_Socket, cb: Callback, timeout: time.Duration = NO_TIMEOUT, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Using the given socket, accepts the next incoming connection, calling the callback when that happens.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under accept_poly, accept_poly2, and accept_poly3.

    Inputs:
    socket: A bound and listening socket associated with the event loop cb: The callback to be called when the operation finishes, Operation.accept will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    accept_poly ¶

    accept_poly :: proc(socket: net.TCP_Socket, p: $T, cb: $C/proc(op: ^Operation, p: $T), timeout: time.Duration = NO_TIMEOUT, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Using the given socket, accepts the next incoming connection, calling the callback when that happens.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: A bound and listening socket associated with the event loop p: User data, the callback will receive this as it's second argument cb: The callback to be called when the operation finishes, Operation.accept will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    accept_poly2 ¶

    accept_poly2 :: proc(
    	socket:  net.TCP_Socket, 
    	p:       $T, 
    	p2:      $T2, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Using the given socket, accepts the next incoming connection, calling the callback when that happens.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: A bound and listening socket associated with the event loop p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument cb: The callback to be called when the operation finishes, Operation.accept will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    accept_poly3 ¶

    accept_poly3 :: proc(
    	socket:  net.TCP_Socket, 
    	p:       $T, 
    	p2:      $T2, 
    	p3:      $T3, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Using the given socket, accepts the next incoming connection, calling the callback when that happens.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: A bound and listening socket associated with the event loop p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument p3: User data, the callback will receive this as it's fourth argument cb: The callback to be called when the operation finishes, Operation.accept will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    acquire_thread_event_loop ¶

    acquire_thread_event_loop :: proc() -> General_Error {…}
     

    Initialize or increment the reference counted event loop for the current thread.

    associate_handle ¶

    associate_handle :: proc(handle: uintptr, l: ^Event_Loop = nil, loc := #caller_location) -> (_Handle, Association_Error) {…}
     

    Associate the given OS handle, not opened through this package, with the event loop.

    Consider using this package's open or open_sync directly instead.

    The handle returned is for convenience, it is actually still the same handle as given. Thus you should not close the given handle.

    On Windows, this can error when a file is not opened with the FILE_FLAG_OVERLAPPED flag. If using core:os, that is set when you specify the O_NONBLOCK flag. There is no way to add that after the fact.

    associate_socket ¶

    associate_socket :: proc(socket: net.Any_Socket, l: ^Event_Loop = nil, loc := #caller_location) -> Association_Error {…}
     

    Associate the given socket, not created through this package, with the event loop.

    Consider using this package's create_socket directly instead.

    close ¶

    close :: proc(subject: Closable, cb: Callback = empty_callback, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Closes the given subject (file or socket).

    Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. For consistent behavior first call remove on in progress IO.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under close_poly, close_poly2, and close_poly3.

    Inputs:
    subject: The subject (socket or file) to close cb: The optional callback to be called when the operation finishes, Operation.close will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    close_poly ¶

    close_poly :: proc(subject: Closable, p: $T, cb: $C/proc(op: ^Operation, p: $T), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Closes the given subject (file or socket).

    Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. For consistent behavior first call remove on in progress IO.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    subject: The subject (socket or file) to close p: User data, the callback will receive this as it's second argument cb: The optional callback to be called when the operation finishes, Operation.close will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    close_poly2 ¶

    close_poly2 :: proc(subject: Closable, p: $T, p2: $T2, cb: $C/proc(op: ^Operation, p: $T, p2: $T2), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Closes the given subject (file or socket).

    Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. For consistent behavior first call remove on in progress IO.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    subject: The subject (socket or file) to close p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument cb: The optional callback to be called when the operation finishes, Operation.close will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    close_poly3 ¶

    close_poly3 :: proc(
    	subject: Closable, 
    	p:       $T, 
    	p2:      $T2, 
    	p3:      $T3, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Closes the given subject (file or socket).

    Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. For consistent behavior first call remove on in progress IO.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    subject: The subject (socket or file) to close p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument p3: User data, the callback will receive this as it's fourth argument cb: The optional callback to be called when the operation finishes, Operation.close will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    create_socket ¶

    create_socket :: proc(family: net.Address_Family, protocol: net.Socket_Protocol, l: ^Event_Loop = nil, loc := #caller_location) -> (socket: net.Any_Socket, err: net.Create_Socket_Error) {…}
     

    Creates a socket for use in nbio and relates it to the given event loop.

    Inputs:
    family: Should this be an IP4 or IP6 socket protocol: The type of socket (TCP or UDP) l: The event loop to associate it with, defaults to the current thread's loop

    Returns:
    socket: The created socket, consider create_{udp|tcp}_socket for a typed socket instead of the union err: A network error (Create_Socket_Error, or Set_Blocking_Error) which happened while opening

    create_tcp_socket ¶

    create_tcp_socket :: proc(family: net.Address_Family, l: ^Event_Loop = nil, loc := #caller_location) -> (net.TCP_Socket, net.Create_Socket_Error) {…}
     

    Creates a TCP socket for use in nbio and relates it to the given event loop.

    Inputs:
    family: Should this be an IP4 or IP6 socket l: The event loop to associate it with, defaults to the current thread's loop

    Returns:
    socket: The created TCP socket err: A network error (Create_Socket_Error, or Set_Blocking_Error) which happened while opening

    create_udp_socket ¶

    create_udp_socket :: proc(family: net.Address_Family, l: ^Event_Loop = nil, loc := #caller_location) -> (net.UDP_Socket, net.Create_Socket_Error) {…}
     

    Creates a UDP socket for use in nbio and relates it to the given event loop.

    Inputs:
    family: Should this be an IP4 or IP6 socket l: The event loop to associate it with, defaults to the current thread's loop

    Returns:
    socket: The created UDP socket err: A network error (Create_Socket_Error, or Set_Blocking_Error) which happened while opening

    current_thread_event_loop ¶

    current_thread_event_loop :: proc(loc := #caller_location) -> ^Event_Loop {…}

    detach ¶

    detach :: proc(op: ^Operation) {…}
     

    Detach an operation from the package's lifetime management.

    By default the operation's lifetime is managed by the package and freed after a callback is called. Calling this function detaches the operation from this lifetime. You are expected to call reattach to give the package back this operation.

    dial ¶

    dial :: proc(endpoint: net.Endpoint, cb: Callback, timeout: time.Duration = NO_TIMEOUT, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Dials the given endpoint.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under dial_poly, dial_poly2, and dial_poly3.

    Inputs:
    endpoint: The endpoint to connect to cb: The callback to be called when the operation finishes, Operation.dial will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    dial_poly ¶

    dial_poly :: proc(endpoint: net.Endpoint, p: $T, cb: $C/proc(op: ^Operation, p: $T), timeout: time.Duration = NO_TIMEOUT, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Dials the given endpoint.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    endpoint: The endpoint to connect to p: User data, the callback will receive this as it's second argument cb: The callback to be called when the operation finishes, Operation.dial will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    dial_poly2 ¶

    dial_poly2 :: proc(
    	endpoint: net.Endpoint, 
    	p:        $T, 
    	p2:       $T2, 
    	cb:       $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	timeout:  time.Duration = NO_TIMEOUT, 
    	l:        ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Dials the given endpoint.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    endpoint: The endpoint to connect to p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument cb: The callback to be called when the operation finishes, Operation.dial will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    dial_poly3 ¶

    dial_poly3 :: proc(
    	endpoint: net.Endpoint, 
    	p:        $T, 
    	p2:       $T2, 
    	p3:       $T3, 
    	cb:       $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	timeout:  time.Duration = NO_TIMEOUT, 
    	l:        ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Dials the given endpoint.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    endpoint: The endpoint to connect to p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument p3: User data, the callback will receive this as it's fourth argument cb: The callback to be called when the operation finishes, Operation.dial will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    error_string_recv ¶

    error_string_recv :: proc(recv_err: net.Recv_Error) -> string {…}

    error_string_send ¶

    error_string_send :: proc(send_err: net.Send_Error) -> string {…}

    error_string_sendfile ¶

    error_string_sendfile :: proc(send_err: Send_File_Error) -> string {…}

    exec ¶

    exec :: proc(op: ^Operation, trigger_wake_up: bool = true) {…}
     

    Execute an operation.

    If the operation is attached to another thread's event loop, it is queued to be executed on that event loop, optionally waking that loop up (from a blocking tick) with trigger_wake_up.

    listen_tcp ¶

    listen_tcp :: proc(endpoint: net.Endpoint, backlog: int = 1000, l: ^Event_Loop = nil, loc := #caller_location) -> (socket: net.TCP_Socket, err: net.Network_Error) {…}
     

    Creates a socket, sets non blocking mode, relates it to the given IO, binds the socket to the given endpoint and starts listening.

    Inputs:
    endpoint: Where to bind the socket to backlog: The maximum length to which the queue of pending connections may grow, before refusing connections l: The event loop to associate the socket with, defaults to the current thread's loop

    Returns:
    socket: The opened, bound and listening socket err: A network error (Create_Socket_Error, Bind_Error, or Listen_Error) that has happened

    next_tick ¶

    next_tick :: proc(cb: Callback, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Schedules an operation that completes on the next event loop tick.

    This is equivalent to timeout(0, ...).

    next_tick_poly ¶

    next_tick_poly :: proc(p: $T, cb: $C/proc(op: ^Operation, p: $T), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Schedules an operation that completes on the next event loop tick.

    This is equivalent to timeout_poly(0, ...).

    next_tick_poly2 ¶

    next_tick_poly2 :: proc(p: $T, p2: $T2, cb: $C/proc(op: ^Operation, p: $T, p2: $T2), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Schedules an operation that completes on the next event loop tick.

    This is equivalent to timeout_poly2(0, ...).

    next_tick_poly3 ¶

    next_tick_poly3 :: proc(p: $T, p2: $T2, p3: $T3, cb: $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Schedules an operation that completes on the next event loop tick.

    This is equivalent to timeout_poly3(0, ...).

    now ¶

    now :: proc() -> time.Time {…}
     

    Returns the current time (cached at most at the beginning of the current tick).

    num_waiting ¶

    num_waiting :: proc(l: runtime.Maybe($T=^Event_Loop) = nil) -> int {…}
     

    Returns the number of in-progress operations to be completed on the event loop.

    open ¶

    open :: proc(
    	path: string, 
    	cb:   Callback, 
    	mode: bit_set[File_Flag; int] = {.Read}, 
    	perm: Permissions = Permissions_Default_File, 
    	dir:  _Handle = CWD, 
    	l:    ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Opens a file and associates it with the event loop.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under open_poly, open_poly2, and open_poly3.

    Inputs:
    path: Path to the file, if not absolute: relative from dir cb: The callback to be called when the operation finishes, Operation.open will contain results mode: File open mode flags, defaults to read-only perm: Permissions to use when creating a file, defaults to read+write for everybody dir: Directory that path is relative from (if it is relative), defaults to the current working directory l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    open_poly ¶

    open_poly :: proc(
    	path: string, 
    	p:    $T, 
    	cb:   $C/proc(op: ^Operation, p: $T), 
    	mode: bit_set[File_Flag; int] = {.Read}, 
    	perm: Permissions = Permissions_Default_File, 
    	dir:  _Handle = CWD, 
    	l:    ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Opens a file and associates it with the event loop.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    path: Path to the file, if not absolute: relative from dir p: User data, the callback will receive this as its second argument cb: The callback to be called when the operation finishes, Operation.open will contain results mode: File open mode flags, defaults to read-only perm: Permissions to use when creating a file, defaults to read+write for everybody dir: Directory that path is relative from (if it is relative), defaults to the current working directory l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    open_poly2 ¶

    open_poly2 :: proc(
    	path: string, 
    	p:    $T, 
    	p2:   $T2, 
    	cb:   $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	mode: bit_set[File_Flag; int] = {.Read}, 
    	perm: Permissions = Permissions_Default_File, 
    	dir:  _Handle = CWD, 
    	l:    ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Opens a file and associates it with the event loop.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    path: Path to the file, if not absolute: relative from dir p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument cb: The callback to be called when the operation finishes, Operation.open will contain results mode: File open mode flags, defaults to read-only perm: Permissions to use when creating a file, defaults to read+write for everybody dir: Directory that path is relative from (if it is relative), defaults to the current working directory l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    open_poly3 ¶

    open_poly3 :: proc(
    	path: string, 
    	p:    $T, 
    	p2:   $T2, 
    	p3:   $T3, 
    	cb:   $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	mode: bit_set[File_Flag; int] = {.Read}, 
    	perm: Permissions = Permissions_Default_File, 
    	dir:  _Handle = CWD, 
    	l:    ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Asynchronously opens a file and associates it with the event loop.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    path: Path to the file, if not absolute: relative from dir p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument p3: User data, the callback will receive this as its fourth argument cb: The callback to be called when the operation finishes, Operation.open will contain results mode: File open mode flags, defaults to read-only perm: Permissions to use when creating a file, defaults to read+write for everybody dir: Directory that path is relative from (if it is relative), defaults to the current working directory l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    open_sync ¶

    open_sync :: proc(
    	path: string, 
    	dir:  _Handle = CWD, 
    	mode: bit_set[File_Flag; int] = {.Read}, 
    	perm: Permissions = Permissions_Default_File, 
    	l:    ^Event_Loop = nil, 
    	loc := #caller_location, 
    ) -> (handle: _Handle, err: FS_Error) {…}
     

    Opens a file and associates it with the event loop.

    Inputs:
    path: path to the file, if not absolute: relative from dir dir: directory that path is relative from (if it is relative), defaults to the current working directory mode: open mode, defaults to read-only perm: permissions to use when creating a file, defaults to read+write for everybody l: event loop to associate the file with, defaults to the current thread's

    Returns:
    handle: The file handle err: An error if it occurred

    poll ¶

    poll :: proc(socket: net.Any_Socket, event: Poll_Event, cb: Callback, timeout: time.Duration = NO_TIMEOUT, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Poll a socket for readiness.

    NOTE: this is provided to help with "legacy" APIs that require polling behavior. If you can avoid it and use the other procs in this package, do so.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under poll_poly, poll_poly2, and poll_poly3.

    Inputs:
    socket: Socket to poll that is associated with the event loop event: Event to poll for cb: The callback to be called when the operation finishes, Operation.poll will contain results timeout: Optional timeout for the operation, the callback will receive a .Timeout result after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    poll_poly ¶

    poll_poly :: proc(
    	socket:  net.Any_Socket, 
    	event:   Poll_Event, 
    	p:       $T, 
    	cb:      $C/proc(op: ^Operation, p: $T), 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Poll a socket for readiness.

    NOTE: this is provided to help with "legacy" APIs that require polling behavior. If you can avoid it and use the other procs in this package, do so.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: Socket to poll that is associated with the event loop event: Event to poll for p: User data, the callback will receive this as its second argument cb: The callback to be called when the operation finishes, Operation.poll will contain results timeout: Optional timeout for the operation, the callback will receive a .Timeout result after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    poll_poly2 ¶

    poll_poly2 :: proc(
    	socket:  net.Any_Socket, 
    	event:   Poll_Event, 
    	p:       $T, 
    	p2:      $T2, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Poll a socket for readiness.

    NOTE: this is provided to help with "legacy" APIs that require polling behavior. If you can avoid it and use the other procs in this package, do so.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: Socket to poll that is associated with the event loop event: Event to poll for p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument cb: The callback to be called when the operation finishes, Operation.poll will contain results timeout: Optional timeout for the operation, the callback will receive a .Timeout result after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    poll_poly3 ¶

    poll_poly3 :: proc(
    	socket:  net.Any_Socket, 
    	event:   Poll_Event, 
    	p:       $T, 
    	p2:      $T2, 
    	p3:      $T3, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Poll a socket for readiness.

    NOTE: this is provided to help with "legacy" APIs that require polling behavior. If you can avoid it and use the other procs in this package, do so.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: Socket to poll that is associated with the event loop event: Event to poll for p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument p3: User data, the callback will receive this as its fourth argument cb: The callback to be called when the operation finishes, Operation.poll will contain results timeout: Optional timeout for the operation, the callback will receive a .Timeout result after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_accept ¶

    prep_accept :: proc(socket: net.TCP_Socket, cb: Callback, timeout: time.Duration = NO_TIMEOUT, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Retrieves and preps an operation to do an accept without executing it.

    Executing can then be done with the exec procedure.

    The timeout is calculated from the time when this procedure was called, not from when it's executed.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    socket: A bound and listening socket associated with the event loop cb: The callback to be called when the operation finishes, Operation.accept will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_close ¶

    prep_close :: proc(subject: Closable, cb: Callback = empty_callback, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Retrieves and preps an operation to do a close without executing it.

    Executing can then be done with the exec procedure.

    Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. For consistent behavior first call remove on in progress IO.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    subject: The subject (socket or file) to close cb: The optional callback to be called when the operation finishes, Operation.close will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_dial ¶

    prep_dial :: proc(endpoint: net.Endpoint, cb: Callback, timeout: time.Duration = NO_TIMEOUT, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Retrieves and preps an operation to do a dial operation without executing it.

    Executing can then be done with the exec procedure.

    The timeout is calculated from the time when this procedure was called, not from when it's executed.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    endpoint: The endpoint to connect to cb: The callback to be called when the operation finishes, Operation.dial will contain results timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_next_tick ¶

    prep_next_tick :: proc(cb: Callback, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Retrieves and preps an operation that completes on the next event loop tick.

    This is equivalent to prep_timeout(0, ...).

    prep_open ¶

    prep_open :: proc(
    	path: string, 
    	cb:   Callback, 
    	mode: bit_set[File_Flag; int] = {.Read}, 
    	perm: Permissions = Permissions_Default_File, 
    	dir:  _Handle = CWD, 
    	l:    ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Retrieves and preps an operation to open a file without executing it.

    Executing can then be done with the exec procedure.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    path: Path to the file, if not absolute: relative from dir cb: The callback to be called when the operation finishes, Operation.open will contain results mode: File open mode flags, defaults to read-only perm: Permissions to use when creating a file, defaults to read+write for everybody dir: Directory that path is relative from (if it is relative), defaults to the current working directory l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_poll ¶

    prep_poll :: proc(socket: net.Any_Socket, event: Poll_Event, cb: Callback, timeout: time.Duration = NO_TIMEOUT, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Retrieves and preps an operation to poll a socket without executing it.

    Executing can then be done with the exec procedure.

    The timeout is calculated from the time when this procedure was called, not from when it's executed.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    socket: Socket to poll that is associated with the event loop event: Event to poll for cb: The callback to be called when the operation finishes, Operation.poll will contain results timeout: Optional timeout for the operation, the callback will receive a .Timeout result after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_read ¶

    prep_read :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	cb:      Callback, 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Retrieves and preps a positional read operation without executing it.

    This is a pread-style operation: the read starts at the given offset and does not modify the handle's current file position.

    Executing can then be done with the exec procedure.

    The timeout is calculated from the time when this procedure was called, not from when it's executed.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    handle: Handle to read from offset: Offset to read from buf: Buffer to read data into (must not be empty) cb: The callback to be called when the operation finishes, Operation.read will contain results all: Whether to read until the buffer is full or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_recv ¶

    prep_recv :: proc(
    	socket:  net.Any_Socket, 
    	bufs:    [][]u8, 
    	cb:      Callback, 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Retrieves and preps an operation to do a receive without executing it.

    Executing can then be done with the exec procedure.

    To avoid ambiguity between a closed connection and a 0-byte read, the provided buffers must have a total capacity greater than 0.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    The timeout is calculated from the time when this procedure was called, not from when it's executed.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    socket: The socket to receive from bufs: Buffers to fill with received data cb: The callback to be called when the operation finishes, Operation.recv will contain results all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_send ¶

    prep_send :: proc(
    	socket:   net.Any_Socket, 
    	bufs:     [][]u8, 
    	cb:       Callback, 
    	endpoint: net.Endpoint = {}, 
    	all:      bool = true, 
    	timeout:  time.Duration = NO_TIMEOUT, 
    	l:        ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Retrieves and preps an operation to do a send without executing it.

    Executing can then be done with the exec procedure.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    The timeout is calculated from the time when this procedure was called, not from when it's executed.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    socket: The socket to send to bufs: Buffers containing the data to send cb: The callback to be called when the operation finishes, Operation.send will contain results endpoint: The destination endpoint (UDP only, ignored for TCP) all: If true, the operation ensures all data is sent before completing timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_sendfile ¶

    prep_sendfile :: proc(
    	socket:           net.TCP_Socket, 
    	file:             _Handle, 
    	cb:               Callback, 
    	offset:           int = 0, 
    	nbytes:           int = SEND_ENTIRE_FILE, 
    	progress_updates: bool = false, 
    	timeout:          time.Duration = NO_TIMEOUT, 
    	l:                ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Retrieves and preps an operation to send a file over a socket without executing it.

    Executing can then be done with the exec procedure.

    This uses high-performance zero-copy system calls where available. Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    socket: The destination TCP socket file: The source file handle cb: The callback to be called when data is sent (if progress_updates is true) or the operation completes offset: Byte offset to start reading from the file nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) progress_updates: If true, the callback fires multiple times to report progress, sent == nbytes means te operation completed timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the final callback is called

    prep_stat ¶

    prep_stat :: proc(handle: _Handle, cb: Callback, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Retrieves and preps an operation to stat a handle without executing it.

    Executing can then be done with the exec procedure.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    handle: Handle to retrieve stat cb: The callback to be called when the operation finishes, Operation.stat will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_timeout ¶

    prep_timeout :: proc(duration: time.Duration, cb: Callback, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Retrieves and preps a timeout operation without executing it.

    Executing can then be done with the exec procedure.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    duration: Duration to wait before the operation completes cb: The callback to be called when the operation finishes l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    prep_write ¶

    prep_write :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	cb:      Callback, 
    	all:     bool = true, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Retrieves and preps a positional write operation without executing it.

    This is a pwrite-style operation: the write starts at the given offset and does not modify the handle's current file position.

    Executing can then be done with the exec procedure.

    The timeout is calculated from the time when this procedure was called, not from when it's executed.

    Any user data can be set on the returned operation's user_data field.

    Inputs:
    handle: Handle to write to offset: Offset to write to buf: Buffer containing data to write (must not be empty) cb: The callback to be called when the operation finishes, Operation.write will contain results all: Whether to write until the entire buffer is written or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    read ¶

    read :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	cb:      Callback, 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Reads data from a handle at a specific offset.

    This is a pread-style operation: the read starts at the given offset and does not modify the handle's current file position.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under read_poly, read_poly2, and read_poly3.

    Inputs:
    handle: Handle to read from offset: Offset to read from buf: Buffer to read data into (must not be empty) cb: The callback to be called when the operation finishes, Operation.read will contain results all: Whether to read until the buffer is full or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    read_entire_file ¶

    read_entire_file :: proc(
    	path:      string, 
    	user_data: rawptr, 
    	cb:        Read_Entire_File_Callback, 
    	allocator := context.allocator, 
    	dir:       _Handle = CWD, 
    	l:         ^Event_Loop = nil, 
    	loc := #caller_location, 
    ) {…}
     

    Combines multiple operations (open, stat, read, close) into one that reads an entire regular file.

    The error contains the operation that the error happened on.

    Inputs:
    path: path to the file, if not absolute: relative from dir user_data: a pointer passed through into the callback cb: the callback to call once completed, called with the user data, file data, and an optional error allocator: the allocator to allocate the file's contents onto dir: directory that path is relative from (if it is relative), defaults to the current working directory l: event loop to execute the operation on

    read_poly ¶

    read_poly :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	p:       $T, 
    	cb:      $C/proc(op: ^Operation, p: $T), 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Reads data from a handle at a specific offset.

    This is a pread-style operation: the read starts at the given offset and does not modify the handle's current file position.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to read from offset: Offset to read from buf: Buffer to read data into (must not be empty) p: User data, the callback will receive this as its second argument cb: The callback to be called when the operation finishes, Operation.read will contain results all: Whether to read until the buffer is full or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    read_poly2 ¶

    read_poly2 :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	p:       $T, 
    	p2:      $T2, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Reads data from a handle at a specific offset.

    This is a pread-style operation: the read starts at the given offset and does not modify the handle's current file position.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to read from offset: Offset to read from buf: Buffer to read data into (must not be empty) p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument cb: The callback to be called when the operation finishes, Operation.read will contain results all: Whether to read until the buffer is full or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    read_poly3 ¶

    read_poly3 :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	p:       $T, 
    	p2:      $T2, 
    	p3:      $T3, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Reads data from a handle at a specific offset.

    This is a pread-style operation: the read starts at the given offset and does not modify the handle's current file position.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to read from offset: Offset to read from buf: Buffer to read data into (must not be empty) p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument p3: User data, the callback will receive this as its fourth argument cb: The callback to be called when the operation finishes, Operation.read will contain results all: Whether to read until the buffer is full or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    reattach ¶

    reattach :: proc(op: ^Operation) {…}
     

    Reattach an operation to the package's lifetime management.

    recv ¶

    recv :: proc(
    	socket:  net.Any_Socket, 
    	bufs:    [][]u8, 
    	cb:      Callback, 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Receives data from the socket.

    If the operation completes with 0 bytes received and no error, it indicates the connection was closed by the peer.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under recv_poly, recv_poly2, and recv_poly3.

    Inputs:
    socket: The socket to receive from bufs: Buffers to fill with received data cb: The callback to be called when the operation finishes, Operation.recv will contain results all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    recv_poly ¶

    recv_poly :: proc(
    	socket:  net.Any_Socket, 
    	bufs:    [][]u8, 
    	p:       $T, 
    	cb:      $C/proc(op: ^Operation, p: $T), 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Receives data from the socket.

    If the operation completes with 0 bytes received and no error, it indicates the connection was closed by the peer.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The socket to receive from bufs: Buffers to fill with received data p: User data, the callback will receive this as it's second argument cb: The callback to be called when the operation finishes, Operation.recv will contain results all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    recv_poly2 ¶

    recv_poly2 :: proc(
    	socket:  net.Any_Socket, 
    	bufs:    [][]u8, 
    	p:       $T, 
    	p2:      $T2, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Receives data from the socket.

    If the operation completes with 0 bytes received and no error, it indicates the connection was closed by the peer.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The socket to receive from bufs: Buffers to fill with received data p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument cb: The callback to be called when the operation finishes, Operation.recv will contain results all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    recv_poly3 ¶

    recv_poly3 :: proc(
    	socket:  net.Any_Socket, 
    	bufs:    [][]u8, 
    	p:       $T, 
    	p2:      $T2, 
    	p3:      $T3, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	all:     bool = false, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Receives data from the socket.

    If the operation completes with 0 bytes received and no error, it indicates the connection was closed by the peer.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The socket to receive from bufs: Buffers to fill with received data p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument p3: User data, the callback will receive this as it's fourth argument cb: The callback to be called when the operation finishes, Operation.recv will contain results all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    release_thread_event_loop ¶

    release_thread_event_loop :: proc() {…}
     

    Destroy or decrease the reference counted event loop for the current thread.

    remove ¶

    remove :: proc(target: ^Operation) {…}
     

    Remove the given operation from the event loop. The callback of it won't be called and resources are freed.

    Calling remove: Cancels the operation if it has not yet completed Prevents the callback from being called

    Cancellation via remove is final and silent: The callback will never be invoked No error is delivered The operation must be considered dead after removal

    WARN: the operation could have already been (partially or completely) completed.

      A send with `all` set to true could have sent a portion already.
      But also, a send that could be completed without blocking could have been completed.
      You just won't get a callback.
    
    

    WARN: once an operation's callback is called it can not be removed anymore (use after free).

    WARN: needs to be called from the thread of the event loop the target belongs to.

    Common use would be to cancel a timeout, remove a polling, or remove an accept before calling close on it's socket.

    run ¶

    run :: proc() -> General_Error {…}
     

    Runs the event loop by ticking in a loop until there is no more work to be done.

    run_until ¶

    run_until :: proc(done: ^bool) -> General_Error {…}
     

    Runs the event loop by ticking in a loop until there is no more work to be done, or the flag done is true.

    send ¶

    send :: proc(
    	socket:   net.Any_Socket, 
    	bufs:     [][]u8, 
    	cb:       Callback, 
    	endpoint: net.Endpoint = {}, 
    	all:      bool = true, 
    	timeout:  time.Duration = NO_TIMEOUT, 
    	l:        ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Sends data to the socket.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under send_poly, send_poly2, and send_poly3.

    Inputs:
    socket: The socket to send to bufs: Buffers containing the data to send cb: The callback to be called when the operation finishes, Operation.send will contain results endpoint: The destination endpoint (UDP only, ignored for TCP) all: If true, the operation ensures all data is sent before completing timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    send_poly ¶

    send_poly :: proc(
    	socket:   net.Any_Socket, 
    	bufs:     [][]u8, 
    	p:        $T, 
    	cb:       $C/proc(op: ^Operation, p: $T), 
    	endpoint: net.Endpoint = {}, 
    	all:      bool = true, 
    	timeout:  time.Duration = NO_TIMEOUT, 
    	l:        ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Sends data to the socket.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The socket to send to bufs: Buffers containing the data to send p: User data, the callback will receive this as it's second argument cb: The callback to be called when the operation finishes, Operation.send will contain results endpoint: The destination endpoint (UDP only, ignored for TCP) all: If true, the operation ensures all data is sent before completing timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    send_poly2 ¶

    send_poly2 :: proc(
    	socket:   net.Any_Socket, 
    	bufs:     [][]u8, 
    	p:        $T, 
    	p2:       $T2, 
    	cb:       $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	endpoint: net.Endpoint = {}, 
    	all:      bool = true, 
    	timeout:  time.Duration = NO_TIMEOUT, 
    	l:        ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Sends data to the socket.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The socket to send to bufs: Buffers containing the data to send p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument cb: The callback to be called when the operation finishes, Operation.send will contain results endpoint: The destination endpoint (UDP only, ignored for TCP) all: If true, the operation ensures all data is sent before completing timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    send_poly3 ¶

    send_poly3 :: proc(
    	socket:   net.Any_Socket, 
    	bufs:     [][]u8, 
    	p:        $T, 
    	p2:       $T2, 
    	p3:       $T3, 
    	cb:       $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	endpoint: net.Endpoint = {}, 
    	all:      bool = true, 
    	timeout:  time.Duration = NO_TIMEOUT, 
    	l:        ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Sends data to the socket.

    The bufs slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The socket to send to bufs: Buffers containing the data to send p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument p3: User data, the callback will receive this as it's fourth argument cb: The callback to be called when the operation finishes, Operation.send will contain results endpoint: The destination endpoint (UDP only, ignored for TCP) all: If true, the operation ensures all data is sent before completing timeout: Optional timeout for the operation, the callback will get a .Timeout error after that duration l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    sendfile ¶

    sendfile :: proc(
    	socket:           net.TCP_Socket, 
    	file:             _Handle, 
    	cb:               Callback, 
    	offset:           int = 0, 
    	nbytes:           int = SEND_ENTIRE_FILE, 
    	progress_updates: bool = false, 
    	timeout:          time.Duration = NO_TIMEOUT, 
    	l:                ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Sends a file over a TCP socket.

    This uses high-performance zero-copy system calls where available. Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under sendfile_poly, sendfile_poly2, and sendfile_poly3.

    Inputs:
    socket: The destination TCP socket file: The source file handle cb: The callback to be called when data is sent (if progress_updates is true) or the operation completes offset: Byte offset to start reading from the file nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) progress_updates: If true, the callback fires multiple times to report progress, sent == nbytes means te operation completed timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the final callback is called

    sendfile_poly ¶

    sendfile_poly :: proc(
    	socket:           net.TCP_Socket, 
    	file:             _Handle, 
    	p:                $T, 
    	cb:               $C/proc(op: ^Operation, p: $T), 
    	offset:           int = 0, 
    	nbytes:           int = SEND_ENTIRE_FILE, 
    	progress_updates: bool = false, 
    	timeout:          time.Duration = NO_TIMEOUT, 
    	l:                ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Sends a file over a TCP socket.

    This uses high-performance zero-copy system calls where available. Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The destination TCP socket file: The source file handle p: User data, the callback will receive this as it's second argument cb: The callback to be called when data is sent (if progress_updates is true) or the operation completes offset: Byte offset to start reading from the file nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) progress_updates: If true, the callback fires multiple times to report progress, sent == nbytes means te operation completed timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the final callback is called

    sendfile_poly2 ¶

    sendfile_poly2 :: proc(
    	socket:           net.TCP_Socket, 
    	file:             _Handle, 
    	p:                $T, 
    	p2:               $T2, 
    	cb:               $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	offset:           int = 0, 
    	nbytes:           int = SEND_ENTIRE_FILE, 
    	progress_updates: bool = false, 
    	timeout:          time.Duration = NO_TIMEOUT, 
    	l:                ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Sends a file over a TCP socket.

    This uses high-performance zero-copy system calls where available. Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The destination TCP socket file: The source file handle p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument cb: The callback to be called when data is sent (if progress_updates is true) or the operation completes offset: Byte offset to start reading from the file nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) progress_updates: If true, the callback fires multiple times to report progress, sent == nbytes means te operation completed timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the final callback is called

    sendfile_poly3 ¶

    sendfile_poly3 :: proc(
    	socket:           net.TCP_Socket, 
    	file:             _Handle, 
    	p:                $T, 
    	p2:               $T2, 
    	p3:               $T3, 
    	cb:               $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	offset:           int = 0, 
    	nbytes:           int = SEND_ENTIRE_FILE, 
    	progress_updates: bool = false, 
    	timeout:          time.Duration = NO_TIMEOUT, 
    	l:                ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Sends a file over a TCP socket.

    This uses high-performance zero-copy system calls where available. Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    socket: The destination TCP socket file: The source file handle p: User data, the callback will receive this as it's second argument p2: User data, the callback will receive this as it's third argument p3: User data, the callback will receive this as it's fourth argument cb: The callback to be called when data is sent (if progress_updates is true) or the operation completes offset: Byte offset to start reading from the file nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) progress_updates: If true, the callback fires multiple times to report progress, sent == nbytes means te operation completed timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the final callback is called

    stat ¶

    stat :: proc(handle: _Handle, cb: Callback, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Stats a handle.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under stat_poly, stat_poly2, and stat_poly3.

    Inputs:
    handle: Handle to retrieve status information for cb: The callback to be called when the operation finishes, Operation.stat will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    stat_poly ¶

    stat_poly :: proc(handle: _Handle, p: $T, cb: $C/proc(op: ^Operation, p: $T), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Stats a handle.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to retrieve status information for p: User data, the callback will receive this as its second argument cb: The callback to be called when the operation finishes, Operation.stat will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    stat_poly2 ¶

    stat_poly2 :: proc(handle: _Handle, p: $T, p2: $T2, cb: $C/proc(op: ^Operation, p: $T, p2: $T2), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Stats a handle.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to retrieve status information for p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument cb: The callback to be called when the operation finishes, Operation.stat will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    stat_poly3 ¶

    stat_poly3 :: proc(
    	handle: _Handle, 
    	p:      $T, 
    	p2:     $T2, 
    	p3:     $T3, 
    	cb:     $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	l:      ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Stats a handle.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to retrieve status information for p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument p3: User data, the callback will receive this as its fourth argument cb: The callback to be called when the operation finishes, Operation.stat will contain results l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    tick ¶

    tick :: proc(timeout: time.Duration = NO_TIMEOUT) -> General_Error {…}
     

    Each time you call this the implementation checks its state and calls any callbacks which are ready. You would typically call this in a loop.

    Blocks for up-to timeout waiting for events if there is nothing to do.

    timeout ¶

    timeout :: proc(duration: time.Duration, cb: Callback, l: ^Event_Loop = nil) -> ^Operation {…}
     

    Schedules a timeout that completes after the given duration.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under timeout_poly, timeout_poly2, and timeout_poly3.

    Inputs:
    duration: Duration to wait before the operation completes cb: The callback to be called when the operation finishes l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    timeout_poly ¶

    timeout_poly :: proc(dur: time.Duration, p: $T, cb: $C/proc(op: ^Operation, p: $T), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Schedules a timeout that completes after the given duration.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    dur: Duration to wait before the operation completes p: User data, the callback will receive this as its second argument cb: The callback to be called when the operation finishes l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    timeout_poly2 ¶

    timeout_poly2 :: proc(dur: time.Duration, p: $T, p2: $T2, cb: $C/proc(op: ^Operation, p: $T, p2: $T2), l: ^Event_Loop = nil) -> ^Operation {…}
     

    Schedules a timeout that completes after the given duration.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    dur: Duration to wait before the operation completes p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument cb: The callback to be called when the operation finishes l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    timeout_poly3 ¶

    timeout_poly3 :: proc(
    	dur: time.Duration, 
    	p:   $T, 
    	p2:  $T2, 
    	p3:  $T3, 
    	cb:  $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	l:   ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Schedules a timeout that completes after the given duration.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    dur: Duration to wait before the operation completes p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument p3: User data, the callback will receive this as its fourth argument cb: The callback to be called when the operation finishes l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    wake_up ¶

    wake_up :: proc(l: ^Event_Loop) {…}
     

    Wake up an event loop on another thread which may be blocking for completed operations.

    Commonly used with exec from a worker thread to have the event loop pick up that work. Note that by default exec already calls this procedure.

    write ¶

    write :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	cb:      Callback, 
    	all:     bool = true, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Writes data to a handle at a specific offset.

    This is a pwrite-style operation: the write starts at the given offset and does not modify the handle's current file position.

    Any user data can be set on the returned operation's user_data field. Polymorphic variants for type safe user data are available under write_poly, write_poly2, and write_poly3.

    Inputs:
    handle: Handle to write to offset: Offset to write to buf: Buffer containing data to write (must not be empty) cb: The callback to be called when the operation finishes, Operation.write will contain results all: Whether to write until the entire buffer is written or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    write_poly ¶

    write_poly :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	p:       $T, 
    	cb:      $C/proc(op: ^Operation, p: $T), 
    	all:     bool = true, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Writes data to a handle at a specific offset.

    This is a pwrite-style operation: the write starts at the given offset and does not modify the handle's current file position.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to write to offset: Offset to write to buf: Buffer containing data to write (must not be empty) p: User data, the callback will receive this as its second argument cb: The callback to be called when the operation finishes, Operation.write will contain results all: Whether to write until the entire buffer is written or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    write_poly2 ¶

    write_poly2 :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	p:       $T, 
    	p2:      $T2, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2), 
    	all:     bool = true, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Writes data to a handle at a specific offset.

    This is a pwrite-style operation: the write starts at the given offset and does not modify the handle's current file position.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to write to offset: Offset to write to buf: Buffer containing data to write (must not be empty) p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument cb: The callback to be called when the operation finishes, Operation.write will contain results all: Whether to write until the entire buffer is written or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    write_poly3 ¶

    write_poly3 :: proc(
    	handle:  _Handle, 
    	offset:  int, 
    	buf:     []u8, 
    	p:       $T, 
    	p2:      $T2, 
    	p3:      $T3, 
    	cb:      $C/proc(op: ^Operation, p: $T, p2: $T2, p3: $T3), 
    	all:     bool = true, 
    	timeout: time.Duration = NO_TIMEOUT, 
    	l:       ^Event_Loop = nil, 
    ) -> ^Operation {…}
     

    Writes data to a handle at a specific offset.

    This is a pwrite-style operation: the write starts at the given offset and does not modify the handle's current file position.

    This procedure uses polymorphism for type safe user data up to a certain size.

    Inputs:
    handle: Handle to write to offset: Offset to write to buf: Buffer containing data to write (must not be empty) p: User data, the callback will receive this as its second argument p2: User data, the callback will receive this as its third argument p3: User data, the callback will receive this as its fourth argument cb: The callback to be called when the operation finishes, Operation.write will contain results all: Whether to write until the entire buffer is written or an error occurs timeout: Optional timeout for the operation l: Event loop to associate the operation with, defaults to the current thread's loop

    Returns:
    A non-nil pointer to the operation, alive until the callback is called

    Procedure Groups

    This section is empty.

    Source Files

    Generation Information

    Generated with odin version dev-2026-01 (vendor "odin") Windows_amd64 @ 2026-01-16 21:14:59.690710400 +0000 UTC