(process-put proc 'jsonrpc-sentinel-cleanup-started t)
(unwind-protect
;; Call all outstanding error handlers
- (maphash (lambda (_id triplet)
- (pcase-let ((`(,_success ,error ,_timeout) triplet))
- (funcall error '(:code -1 :message "Server died"))))
- (jsonrpc--request-continuations connection))
+ (mapc (jsonrpc-lambda (_id _method _success-fn error-fn _timer)
+ (funcall error-fn '(:code -1 :message "Server died")))
+ (jsonrpc--continuations connection))
(jsonrpc--message "Server exited with status %s" (process-exit-status proc))
(delete-process proc)
+ (when-let (p (slot-value connection '-autoport-inferior)) (delete-process p))
(funcall (jsonrpc--on-shutdown connection) connection)))))
-(defvar jsonrpc--in-process-filter nil
- "Non-nil if inside `jsonrpc--process-filter'.")
-
(cl-defun jsonrpc--process-filter (proc string)
"Called when new data STRING has arrived for PROC."
+ (when jsonrpc--in-process-filter
+ ;; Problematic recursive process filters may happen if
+ ;; `jsonrpc-connection-receive', called by us, eventually calls
+ ;; client code which calls `process-send-string' (which see) to,
+ ;; say send a follow-up message. If that happens to writes enough
+ ;; bytes for pending output to be received, we will lose JSONRPC
+ ;; messages. In that case, remove recursiveness by re-scheduling
+ ;; ourselves to run from within a timer as soon as possible
+ ;; (bug#60088)
+ (run-at-time 0 nil #'jsonrpc--process-filter proc string)
+ (cl-return-from jsonrpc--process-filter))
(when (buffer-live-p (process-buffer proc))
(with-current-buffer (process-buffer proc)
- (let* ((jsonrpc--in-process-filter t)
- (connection (process-get proc 'jsonrpc-connection))
- (expected-bytes (jsonrpc--expected-bytes connection)))
+ (let* ((conn (process-get proc 'jsonrpc-connection))
+ (expected-bytes (jsonrpc--expected-bytes conn)))
;; Insert the text, advancing the process marker.
;;
(save-excursion