If you assume there’s almost no crosstalk, you can likely get away with a thread-id and an optimistic mutex per pool: the mutex will only contend if one thread tries to (de)alloc while an other thread has a cross-thread free running.
If you assume there will be more contention than that, then scaling up complexity might be a good idea e.g. lock per size class / arena, or push cross-thread frees to a queue and have the owning thread check the queue once in a while. You can then make that queue lock-free or even wait-free if that is better for your workload / issues.
> Free-ing from another thread can now be a single CAS without needing sophisticated coordination between threads
which may not be the worst thing in the world; depends on what your app does.
afaik neither c nor posix provides portable cas, so while that's probably the best performing solution, it's probably not suitable for musl
discussion in https://news.ycombinator.com/item?id=38619599