Re: A fix for SBCL error "thread local storage exhausted" when creating too many rules

David Scherfgen via Maxima-discuss <[email protected]> Sun, 7 Jun 2026 11:01:13 +0200
Newsgroups gmane.comp.mathematics.maxima.general
Message-ID <CAMTHLKj3qdDGakbEHsWCQ6yABrn-oPdX0gU3RSPo0fVfZLwEYA@mail.gmail.com>
Hi Gunter,

If we ever try to make Maxima thread-safe, then we need to protect the
access to *rule-symbol-pool* using a mutex.
To be honest, I doubt that'll happen, though. There's so much "global
state" in Maxima that's shared between threads.

Best regards
David

Am So., 7. Juni 2026 um 10:56 Uhr schrieb Gunter K�nigsmann <
[email protected]>:

> My only question would be: if we ever introduce multi-threaded work... ...
> as far as I understand stuff stored in thread-local memory won't be shared
> between threads so each thread could make its own assumptions without
> having to fea race conditions.
>
> Didn't look closely enough at the new code to see if the new code would
> allow that, as well.
>
> Having said that I hate running out of thread-local memory as it normally
> is a clear game over situation.
>
> Kind regards,
>
>    Gunter.
>
>
> On 5 June 2026 15:57:21 CEST, David Scherfgen via Maxima-discuss <
> [email protected]> wrote:
>
>> Hi everyone,
>>
>> I've been looking into the annoying bug #4517
>> <https://sourceforge.net/p/maxima/bugs/4517/>, where Maxima crashes on
>> SBCL due to Thread-Local Storage (TLS) exhaustion after repeatedly
>> generating and destroying rules (via defrule, tellsimp, etc.). It
>> famously can be triggered by running the rtest_rules test a few times.
>>
>> The root cause is that the pattern-matching compiler dynamically binds
>> new symbols generated during rule creation. On SBCL, every newly
>> dynamically bound special variable permanently consumes a TLS slot. Even if
>> the rule is subsequently removed, SBCL cannot free the underlying TLS
>> index, eventually causing a hard crash once the limit is reached.
>>
>> To resolve this, I've implemented a reusable symbol pool (
>> *rule-symbol-pool*). The patch modifies matcom.lisp to track all symbols
>> generated for a specific rule via its property list. When a rule is
>> overwritten, or when it is destroyed via kill1-atom in suprv1.lisp,
>> those symbols are completely scrubbed (makunbound, fmakunbound, and
>> property list cleared) and pushed back into the pool for the next rule to
>> recycle. Now, the TLS consumption strictly depends on the rules that exist
>> at the same time, rather than all rules ever created over the lifetime of
>> the session.
>>
>> I'd love to get some feedback on this approach, and I have a specific
>> question for the veterans regarding the historical design: In my patch, I
>> replaced the tr-gensym call in genref with the new pool allocator (
>> get-rule-symbol). Does anyone recall the original rationale for using
>> tr-gensym (which interns the symbol) in genref instead of a standard
>> uninterned gensym, as it is the case in other places in the relevant
>> code? I want to ensure I'm not breaking a subtle dependency with the
>> translator.
>>
>> Note: A visible side effect of this change is that these match variables
>> will now be named RULE-SYMBOL-... rather than TR-GENSYM~... in
>> macro-expanded code.
>>
>> Best regards
>> David Scherfgen
>>
>

_______________________________________________
Maxima-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/maxima-discuss