Subject: bug#78917: feature/igc [PATCH] Avoid chaining finalizers together

From: Helmut Eller <[email-masked]>
Date: Sat, 28 Jun 2025 22:42:15 +0200

On Sat, Jun 28 2025, Pip Cet wrote:

> "Helmut Eller" <[email-masked]> writes:
>
>> Lisp_Finalizers are currently chained together in a doubly linked list.
>> This prevents them from being collected.  I propose that we simply don't
>> use this list with MPS.
>>
>> The first patch is minimalistic: it only skips finalizer_insert when
>> creating finalizers.
>>
>> The second patch is more thorough: it #ifdefs away the prev/next fields
>> entirely.
>
> Looks good, except for the addition of igc--process-messages;
> igc--collect should process *all* messages before returning,

Maybe.  igc-collect (the one from igc.el) could easily call
igc--process-messages, though.

> exposing a function that processes only some of the messages doesn't
> seem useful to me.

It's useful to test finalizes.  It would be more useful to have an API
to test finalizers that works for both MPS and non-MPS configurations.
A candidate is

  (progn (garbage-collect) (accept-process-output))

but I guess that a plain

  (garbage-collect)

is what most people would prefer.

> The test probably should be rewritten to something like this:
>
> ;; Ensure finalizers are collected and bug#78917 doesn't reappear.
> (ert-deftest test-two-finalizers ()
>   ;; this test will usually succeed, but might fail due to unpredictable
>   ;; references to the finalizer on the C stack or elsewhere.
>   :tags '(:igc :unstable)
>   (let* ((garbage-collection-messages t)
>          (finalizer-1-called nil)
>          (finalizer-2-called nil)
>          (finalizer-1 (make-finalizer (lambda (setq finalizer-1-called t))))
>          (finalizer-2 (make-finalizer (lambda (setq finalizer-2-called t)))))
>     (dotimes (_ 3)
>       (igc--collect)
>       (sleep-for 0.1))
>     (should (not finalizer-1-called))
>     (should (not finalizer-2-called))
>     (setq finalizer-1 nil)
>     (dotimes (_ 1)
>       (igc--collect)
>       (accept-process-output nil 1 0 t))
>     (should finalizer-1-called)
>     (should (not finalizer-2-called))))

Have you tried it?  This doesn't work for me.

Helmut