Copy link
@skeeto

skeeto Aug 18, 2021

a solution using Elisp threads, mutexs, and condition variables

Yeah, I've concluded that Emacs' threading support is not only hopelessly broken and useless, but actively dangerous. It's not useful for any purpose. I've been building Emacs with threading disabled for some time now.

It's so simple, to block on the curl process's output and completion this way.

This is a pretty handy trick when you need it. I've been using it here and there over the past 8 or 9 years. See: Turning Asynchronous into Synchronous in Elisp and skewer-eval-synchronously (waits on a socket). It's a shame it has to completely block the lisp interpreter, though. A continuation-like version of accept-process-output that saves the call stack but allows the lisp event loop to keep running would have been far more powerful than explicit threads.

By the way, a quick-and-dirty aio curl wrapper looks like this: :-)

(aio-defun curl (url)
  (cl-destructuring-bind (sentinel . promise) (aio-make-callback)
    (let* ((buffer (generate-new-buffer " *curl*"))
           (proc (make-process :name "curl"
                               :buffer buffer
                               :command (list "curl" "--" url)
                               :sentinel sentinel)))
      (aio-await promise)
      (with-current-buffer buffer
        (prog1 (buffer-string)
          (kill-buffer))))))

To wait on this synchronously withaio-wait-for, it would also call accept-process-output internally.

(aio-wait-for (curl "http://localhost:8080/"))

(Unfortunately unwind-protect isn't compatible with generator yielding, and so isn't compatible with aio-await, so no with-temp-buffer or anything like that, hence the manual buffer generate and kill.)