picoev event loop (epoll/kqueue/select) as a Ring extension — cross-platform build scripts
  • C 92.2%
  • Shell 4.7%
  • Ring 1.9%
  • Batchfile 1.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Youssef Saeed 596ab3d8f0 ring-picoev: picoev event loop extension for Ring
Wraps picoev (epoll/kqueue/select) as a Ring extension using the
official conventions: registry list [object,event,code,params,owner],
C trampoline fills params then ring_vm_runcode, owner published as
g_listener = ref(owner) (plain assignment deep-copies).

Thread-safe for one VM shared across threads (thrd_create): a
pthread_mutex_t serializes picoev's process-global state mutations
(init/create_loop/add/del/destroy); picoev_loop_once stays lock-free
per loop. ring_vm_runcode runs outside the explicit VM mutex (it takes
the mutex itself; the non-recursive mutex would self-deadlock).

Build scripts for all supported platforms:
- build.sh        Linux/BSD (gcc or clang; epoll on Linux, kqueue on BSD)
- buildclang.sh   macOS (clang, kqueue -> .dylib)
- buildvc.bat     Windows (MSVC, select -> ring_picoev.dll)
- build-backend.sh  explicit backend selection

Backend is chosen per-OS at build time; only one of picoev_epoll.c /
picoev_kqueue.c / picoev_select.c is compiled with ring_picoev.c.
2026-10-05 03:21:26 +08:00
ext ring-picoev: picoev event loop extension for Ring 2026-10-05 03:21:26 +08:00
.gitignore ring-picoev: picoev event loop extension for Ring 2026-10-05 03:21:26 +08:00
build-backend.sh ring-picoev: picoev event loop extension for Ring 2026-10-05 03:21:26 +08:00
build.sh ring-picoev: picoev event loop extension for Ring 2026-10-05 03:21:26 +08:00
buildclang.sh ring-picoev: picoev event loop extension for Ring 2026-10-05 03:21:26 +08:00
buildvc.bat ring-picoev: picoev event loop extension for Ring 2026-10-05 03:21:26 +08:00
picoev.ring ring-picoev: picoev event loop extension for Ring 2026-10-05 03:21:26 +08:00
README.md ring-picoev: picoev event loop extension for Ring 2026-10-05 03:21:26 +08:00

ring-picoev

A Ring extension that wraps picoev — a small, fast event loop library (epoll on Linux, kqueue on BSD/macOS, select fallback) — exposing it to Ring with the official extension conventions.

Used as the default event loop for the Comet Conquer Online server emulator (game listener on the main thread + JSON-RPC listener on a worker thread, both picoev loops in one process).

API

LoadLib("libring_picoev.so")

picoev_init(max_fd)                     # one-shot, process-global
loop = picoev_create_loop(max_timeout)  # own loop per thread
picoev_add(loop, fd, events, timeout, "on_event()", "owner")
picoev_del(loop, fd)
picoev_loop_once(loop, max_wait_ms)     # blocks up to ~1s (resolution)
picoev_is_active(loop, fd)              # 1/0
picoev_destroy_loop(loop)

# read event params back inside the callback:
p = picoev_eventpara()      # [fd, revents] of the last event
p = picoev_Eventpara(fd, :event)   # per-fd slot

Masks: PICOEV_READ 1, PICOEV_WRITE 2, PICOEV_TIMEOUT 4.

Design (official extension conventions)

  • Each registration is a Ring List [object, event, code, params, owner] (the first four slots are the ringlibuv convention).
  • The C trampoline fills the params sub-list with (fd, revents) via ring_list_adddouble_gc, publishes the active listener as g_listener = ref(owner) (plain assignment deep-copies — see the gotcha), then runs the stored code string with ring_vm_runcode.
  • ring_vm_runcode is called outside the explicit ring_vm_mutexlock (it takes the VM mutex itself; holding the non-recursive mutex across it self-deadlocks).
  • picoev's process-global state (picoev.fds[], picoev.num_loops) is not thread-safe, so all global-state mutations (picoev_init, picoev_create_loop, picoev_add, picoev_del, picoev_destroy_loop) are serialized with a pthread_mutex_t. picoev_loop_once stays lock-free per loop.
  • picoev is level-triggered: handlers must drain their socket (accept()/recv() until EAGAIN) and picoev_del closed fds. Client sockets must be non-blocking.

Building

Drop this repo under the Ring source tree (e.g. <ring>/extensions/ringpicoev/) so ../../language/include and ../../lib resolve, or set RING_INCLUDE / RING_LIB.

  • Linux (gcc or clang, epoll): ./build.sh
  • macOS (clang, kqueue): ./buildclang.sh
  • BSD (gcc/clang, kqueue): ./build.sh (auto-detects)
  • Windows (MSVC, select): buildvc.bat from a VS Developer Prompt
  • Explicit backend: ./build-backend.sh picoev_epoll.c

The backend is chosen per-OS at build time; only one of picoev_epoll.c / picoev_kqueue.c / picoev_select.c is compiled alongside ring_picoev.c.

License

picoev is BSD-licensed (Cybozu Labs, Inc.) — see ext/picoev.h. The Ring binding (ext/ring_picoev.c) is MIT.