Skip to content

Conversation

@llmII
Copy link
Contributor

@llmII llmII commented Dec 13, 2025

Sometimes a unix socket has a 0 status return which indicates the connection immediately succeeded, at which point entering the event loop waiting on the connection to complete actually breaks things.

It seems on FreeBSD with events being edge triggered, we're awaiting a connection to signal it's writeable (to complete the connection) but that never occurs (the event already took place before we registered for the event). Going by status alone to determine if we should enter into the event loop to await the complete connection seems sensible here.


In the process of making jsec run under FreeBSD my tests on unix sockets began failing (hanging). After a lot of investigation we came to the above conclusion (and checked it under linux and freebsd).

This fix has been tested (make test) under both linux and freebsd and confirmed to work both for jsec and for Janet's own tests.


Example hanging test code (runs on linux, fails on freebsd):

# Minimal unix socket hang reproduction for FreeBSD
# 
# On FreeBSD: hangs at net/connect (kqread)
# On Linux: completes successfully
#
# Root cause: connect() on unix sockets returns 0 (success) synchronously
# on FreeBSD, but Janet schedules an async wait for EVFILT_WRITE anyway.
# With edge-triggered kqueue, no event fires since socket is already writable.

(def path "/tmp/janet-unix-minimal.sock")
(when (os/stat path) (os/rm path))

(def server (net/listen :unix path))
(var done false)

(ev/spawn
  (def conn (net/accept server))
  (def msg (ev/read conn 1024))
  (print "Got: " (string msg))
  (ev/close conn)
  (set done true))

(ev/sleep 0.05)

(ev/spawn
  (print "Connecting...")
  # HANGS HERE on FreeBSD - net/connect waits for EVFILT_WRITE that never fires
  (def client (net/connect :unix path))
  (print "Connected!")
  (ev/write client "hello")
  (ev/close client))

(var t 5)
(while (and (not done) (> t 0)) (ev/sleep 0.5) (-- t))

(net/close server)
(when (os/stat path) (os/rm path))
(print (if done "SUCCESS" "HUNG - bug confirmed"))

Sometimes a unix socket has a 0 status return which indicates the connection
immediately succeeded, at which point entering the event loop waiting on the
connection to complete actually breaks things.

It seems on FreeBSD with events being edge triggered, we're awaiting a
connection to signal it's writeable (to complete the connection) but that
never occurs (the event already took place before we registered for the
event). Going by status alone to determine if we should enter into the event
loop to await the complete connection seems sensible here.
@bakpakin bakpakin merged commit d3f5b54 into janet-lang:master Dec 14, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants