- C 92.2%
- Shell 4.7%
- Ring 1.9%
- Batchfile 1.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
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. |
||
| ext | ||
| .gitignore | ||
| build-backend.sh | ||
| build.sh | ||
| buildclang.sh | ||
| buildvc.bat | ||
| picoev.ring | ||
| README.md | ||
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
paramssub-list with(fd, revents)viaring_list_adddouble_gc, publishes the active listener asg_listener = ref(owner)(plain assignment deep-copies — see the gotcha), then runs the stored code string withring_vm_runcode. ring_vm_runcodeis called outside the explicitring_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 apthread_mutex_t.picoev_loop_oncestays lock-free per loop. - picoev is level-triggered: handlers must drain their socket
(
accept()/recv()until EAGAIN) andpicoev_delclosed 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.batfrom 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.