#+build darwin, netbsd, openbsd, freebsd package kqueue when ODIN_OS == .Darwin { foreign import lib "system:System" } else { foreign import lib "system:c" } import "base:intrinsics" import "core:c" import "core:sys/posix" KQ :: posix.FD kqueue :: proc() -> (kq: KQ, err: posix.Errno) { kq = _kqueue() if kq == -1 { err = posix.errno() } return } kevent :: proc(kq: KQ, change_list: []KEvent, event_list: []KEvent, timeout: ^posix.timespec) -> (n_events: c.int, err: posix.Errno) { n_events = _kevent( kq, raw_data(change_list), c.int(len(change_list)), raw_data(event_list), c.int(len(event_list)), timeout, ) if n_events == -1 { n_events = 0 err = posix.errno() } return } Flag :: enum _Flags_Backing { Add = log2(0x0001), // Add event to kq (implies .Enable). Delete = log2(0x0002), // Delete event from kq. Enable = log2(0x0004), // Enable event. Disable = log2(0x0008), // Disable event (not reported). One_Shot = log2(0x0010), // Only report one occurrence. Clear = log2(0x0020), // Clear event state after reporting. Receipt = log2(0x0040), // Force immediate event output. Dispatch = log2(0x0080), // Disable event after reporting. Error = log2(0x4000), // Error, data contains errno. EOF = log2(0x8000), // EOF detected. } Flags :: bit_set[Flag; _Flags_Backing] Filter :: enum _Filter_Backing { Read = _FILTER_READ, // Check for read availability on the file descriptor. Write = _FILTER_WRITE, // Check for write availability on the file descriptor. AIO = _FILTER_AIO, // Attached to AIO requests. VNode = _FILTER_VNODE, // Check for changes to the subject file. Proc = _FILTER_PROC, // Check for changes to the subject process. Signal = _FILTER_SIGNAL, // Check for signals delivered to the process. Timer = _FILTER_TIMER, // Timers. User = _FILTER_USER, // User events. } RW_Flag :: enum u32 { Low_Water_Mark = log2(0x00000001), } RW_Flags :: bit_set[RW_Flag; u32] VNode_Flag :: enum u32 { Delete = log2(0x00000001), // Deleted. Write = log2(0x00000002), // Contents changed. Extend = log2(0x00000004), // Size increased. Attrib = log2(0x00000008), // Attributes changed. Link = log2(0x00000010), // Link count changed. Rename = log2(0x00000020), // Renamed. Revoke = log2(0x00000040), // Access was revoked. } VNode_Flags :: bit_set[VNode_Flag; u32] Proc_Flag :: enum u32 { Exit = log2(0x80000000), // Process exited. Fork = log2(0x40000000), // Process forked. Exec = log2(0x20000000), // Process exec'd. } Proc_Flags :: bit_set[Proc_Flag; u32] Timer_Flag :: enum u32 { Seconds = log2(0x00000001), // Data is seconds. USeconds = log2(_NOTE_USECONDS), // Data is microseconds. Absolute = log2(_NOTE_ABSOLUTE), // Absolute timeout. } Timer_Flags :: bit_set[Timer_Flag; u32] User_Flag :: enum u32 { Trigger = log2(0x01000000), FFAnd = log2(0x40000000), FFOr = log2(0x80000000), } User_Flags :: bit_set[User_Flag; u32] USER_FLAGS_COPY :: User_Flags{.FFOr, .FFAnd} USER_FLAGS_CONTROL_MASK :: transmute(User_Flags)u32(0xc0000000) USER_FLAGS_MASK :: transmute(User_Flags)u32(0x00FFFFFF) // Data is nanoseconds. TIMER_FLAGS_NSECONDS :: _TIMER_FLAGS_NSECONDS when ODIN_OS == .Darwin { _Filter_Backing :: distinct i16 _Flags_Backing :: distinct u16 _FILTER_READ :: -1 _FILTER_WRITE :: -2 _FILTER_AIO :: -3 _FILTER_VNODE :: -4 _FILTER_PROC :: -5 _FILTER_SIGNAL :: -6 _FILTER_TIMER :: -7 _FILTER_USER :: -10 _NOTE_USECONDS :: 0x00000002 _NOTE_NSECONDS :: 0x00000004 _NOTE_ABSOLUTE :: 0x00000008 _TIMER_FLAGS_NSECONDS :: Timer_Flags{Timer_Flag(log2(_NOTE_NSECONDS))} KEvent :: struct #align(4) { // Value used to identify this event. The exact interpretation is determined by the attached filter. ident: uintptr, // Filter for event. filter: Filter, // General flags. flags: Flags, // Filter specific flags. fflags: struct #raw_union { rw: RW_Flags `raw_union_tag:"filter=.Read, filter=.Write"`, vnode: VNode_Flags `raw_union_tag:"filter=.VNode"`, fproc: Proc_Flags `raw_union_tag:"filter=.Proc"`, // vm: VM_Flags, timer: Timer_Flags `raw_union_tag:"filter=.Timer"`, user: User_Flags `raw_union_tag:"filter=.User"`, }, // Filter specific data. data: c.long /* intptr_t */, // Opaque user data passed through the kernel unchanged. udata: rawptr, } } else when ODIN_OS == .FreeBSD { _Filter_Backing :: distinct i16 _Flags_Backing :: distinct u16 _FILTER_READ :: -1 _FILTER_WRITE :: -2 _FILTER_AIO :: -3 _FILTER_VNODE :: -4 _FILTER_PROC :: -5 _FILTER_SIGNAL :: -6 _FILTER_TIMER :: -7 _FILTER_USER :: -11 _NOTE_USECONDS :: 0x00000004 _NOTE_NSECONDS :: 0x00000008 _NOTE_ABSOLUTE :: 0x00000010 _TIMER_FLAGS_NSECONDS :: Timer_Flags{Timer_Flag(log2(_NOTE_NSECONDS))} KEvent :: struct { // Value used to identify this event. The exact interpretation is determined by the attached filter. ident: uintptr, // Filter for event. filter: Filter, // General flags. flags: Flags, // Filter specific flags. fflags: struct #raw_union { rw: RW_Flags `raw_union_tag:"filter=.Read, filter=.Write"`, vnode: VNode_Flags `raw_union_tag:"filter=.VNode"`, fproc: Proc_Flags `raw_union_tag:"filter=.Proc"`, // vm: VM_Flags, timer: Timer_Flags `raw_union_tag:"filter=.Timer"`, user: User_Flags `raw_union_tag:"filter=.User"`, }, // Filter specific data. data: i64, // Opaque user data passed through the kernel unchanged. udata: rawptr, // Extensions. ext: [4]u64, } } else when ODIN_OS == .NetBSD { _Filter_Backing :: distinct u32 _Flags_Backing :: distinct u32 _FILTER_READ :: 0 _FILTER_WRITE :: 1 _FILTER_AIO :: 2 _FILTER_VNODE :: 3 _FILTER_PROC :: 4 _FILTER_SIGNAL :: 5 _FILTER_TIMER :: 6 _FILTER_USER :: 8 _NOTE_USECONDS :: 0x00000002 _NOTE_ABSOLUTE :: 0x00000010 _TIMER_FLAGS_NSECONDS :: Timer_Flags{.Seconds, .USeconds} KEvent :: struct { // Value used to identify this event. The exact interpretation is determined by the attached filter. ident: uintptr, // Filter for event. filter: Filter, // General flags. flags: Flags, // Filter specific flags. fflags: struct #raw_union { rw: RW_Flags `raw_union_tag:"filter=.Read, filter=.Write"`, vnode: VNode_Flags `raw_union_tag:"filter=.VNode"`, fproc: Proc_Flags `raw_union_tag:"filter=.Proc"`, // vm: VM_Flags, timer: Timer_Flags `raw_union_tag:"filter=.Timer"`, user: User_Flags `raw_union_tag:"filter=.User"`, }, // Filter specific data. data: i64, // Opaque user data passed through the kernel unchanged. udata: rawptr, } } else when ODIN_OS == .OpenBSD { _Filter_Backing :: distinct i16 _Flags_Backing :: distinct u16 _FILTER_READ :: -1 _FILTER_WRITE :: -2 _FILTER_AIO :: -3 _FILTER_VNODE :: -4 _FILTER_PROC :: -5 _FILTER_SIGNAL :: -6 _FILTER_TIMER :: -7 _FILTER_USER :: -10 _NOTE_USECONDS :: 0x00000002 _NOTE_NSECONDS :: 0x00000004 _NOTE_ABSOLUTE :: 0x00000010 _TIMER_FLAGS_NSECONDS :: Timer_Flags{Timer_Flag(log2(_NOTE_NSECONDS))} KEvent :: struct #align(4) { // Value used to identify this event. The exact interpretation is determined by the attached filter. ident: uintptr, // Filter for event. filter: Filter, // General flags. flags: Flags, // Filter specific flags. fflags: struct #raw_union { rw: RW_Flags `raw_union_tag:"filter=.Read, filter=.Write"`, vnode: VNode_Flags `raw_union_tag:"filter=.VNode"`, fproc: Proc_Flags `raw_union_tag:"filter=.Proc"`, // vm: VM_Flags, timer: Timer_Flags `raw_union_tag:"filter=.Timer"`, user: User_Flags `raw_union_tag:"filter=.User"`, }, // Filter specific data. data: i64, // Opaque user data passed through the kernel unchanged. udata: rawptr, } } when ODIN_OS == .NetBSD { @(private) LKEVENT :: "__kevent50" } else { @(private) LKEVENT :: "kevent" } @(private) log2 :: intrinsics.constant_log2 foreign lib { @(link_name="kqueue") _kqueue :: proc() -> KQ --- @(link_name=LKEVENT) _kevent :: proc(kq: KQ, change_list: [^]KEvent, n_changes: c.int, event_list: [^]KEvent, n_events: c.int, timeout: ^posix.timespec) -> c.int --- }