iolib icon indicating copy to clipboard operation
iolib copied to clipboard

Add eventfd(2) syscall for linux

Open christophejunke opened this issue 4 months ago • 0 comments

Hi,

This patch exposes eventfd(2).

For reference I also wrote the following read/write functions to interact with the file descriptor returned by the call, but these are not in the patch:

(defun efd-read% (ptr fd)
  (let ((ret (isys:read fd ptr (cffi:foreign-type-size :uint64))))
    (assert (= ret (cffi:foreign-type-size :uint64)))
    (cffi:mem-ref ptr :uint64)))

(defun efd-write% (ptr fd value)
  (check-type value (unsigned-byte 64))
  (setf (cffi:mem-ref ptr :uint64) value)
  (prog1 T
    (let ((ret (isys:write fd ptr (cffi:foreign-type-size :uint64))))
      (assert (= ret (cffi:foreign-type-size :uint64))))))

(defun efd-read (fd)
  (cffi:with-foreign-object (ptr :uint64 1)
    (efd-read% ptr fd)))

(defun efd-write (fd value)
  (check-type value (unsigned-byte 64))
  (cffi:with-foreign-object (ptr :uint64 1)
    (efd-write% ptr fd value)))

If for example we define the following macro:

(defmacro with-eventfd
    ((&key get set efd ((:ptr ptr%)) (initial 0) (flags 0)) &body body)
  (with-gensyms (new)
    (let* ((efd (or efd (gensym "EFD")))
           (ptr (or ptr% (gensym "PTR")))
           (get@ (and get `((,get () (efd-read% ,ptr ,efd)))))
           (set@ (and set `((,set (,new) (efd-write% ,ptr ,efd ,new)))))
           (core `(let ((,efd (iolib/syscalls:eventfd ,initial ,flags)))
                    (unwind-protect (flet (,@get@ ,@set@) ,@body)
                      (isys:close ,efd)))))
      (if ptr%
          core
          `(cffi:with-foreign-object (,ptr :uint64 1) ,core)))))

Then here is a usage example of the syscal to have an interruptible event loop:

  (with-event-base (base)
    (with-eventfd (:efd wakeupfd :get read-wfd :set write-wfd)
      (set-io-handler base wakeupfd :read 
        (lambda (args)
          (declare (ignore args))
          (read-wfd)))
    
      ;; ... others may call (write-wfd 1) to wakeup the event loop

      (event-dispatch base)))

Without eventfd(2), the typical way of doing this is with a pipe. Context: https://stackoverflow.com/questions/79724520/signal-handling-in-multi-threaded-scenario

christophejunke avatar Aug 05 '25 10:08 christophejunke