Skip to content

Instantly share code, notes, and snippets.

@ysbaddaden
Created June 4, 2024 16:04
Show Gist options
  • Save ysbaddaden/aad87ddcb62620dd1b494ef820a5bd35 to your computer and use it in GitHub Desktop.
Save ysbaddaden/aad87ddcb62620dd1b494ef820a5bd35 to your computer and use it in GitHub Desktop.
kqueue.cr
require "c/sys/time"
lib LibC
KQUEUE_CLOEXEC = O_CLOEXEC
# todo: constants
# EV_ADD = ...
# EV_ENABLE = ...
# ...
struct Kevent
ident : SizeT # uintptr_t
filter : Short
flags : UShort
fflags : UInt
data : Int64
udata : Void*
end
fun kqueue : Int
fun kqueue1(flags : Int) : Int # fixme: may be named kqueuex or not be available (depends on the BSD variant)
fun kevent(kq : Int, changelist : Kevent*, nchanges : SizeT, eventlist : Kevent*, nevents : SizeT, timeout : Timespec) : Int
end
{% skip_file unless flag?(:bsd) || flag?(:darwin) %}
require "./c/sys/event"
struct Kqueue
def initialize
{% if LibC.has_method?(:kqueue1) %}
@kq = LibC.kqueue1(LibC::KQUEUE_CLOEXEC)
raise RuntimeError.from_errno("kqueue1") if @kq == -1
{% else %}
@kq = LibC.kqueue
raise RuntimeError.from_errno("kqueue") if @kq == -1
{% unless flag?(:openbsd) %}
ret = LibC.fcntl(LibC::F_SETFD, LibC::FD_CLOEXEC) == -1
raise IO::Error.from_errno("fcntl")
{% end %}
{% end %}
end
def call(changes : Slice(LibC::Kevent)?, events : Slice(LibC::Kevent)?, timeout : Time::Span?) : Int32
if timeout
ts = uninitialized LibC::Timespec
ts.tv_sec = LibC::Long.new!(timeout.seconds)
ts.tv_nsec = LibC::Long.new!(timeout.nanoseconds)
tsp = pointerof(ts)
end
nchanges = changes.try(&.size) || 0
nevents = events.try(&.size) || 0
if LibC.kevent(@kq, changes, nchanges, events, nevents, tsp) == -1
raise RuntimeError.from_errno("kevent")
end
events.try(&.size) || 0
end
def close : Nil
if LibC.close(@kq) == -1
raise RuntimeError.from_errno("close")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment