If you are interested, feel free to go over to the GitHub issue with all details [1], but I intentionally present an abstracted version of the problem here in hope that someone with more knowledge of GHC can guide us without having to learn all details.
We are calling a C API from Haskell. This C code allocates memory and has API methods to subsequently free created objects. We register these deallocation methods as finalizers [2] with the Haskell garbage collector for the corresponding objects. Everything works as expected without multi-threading.
However, when programs allocate and deallocate many objects and are compiled multi-threaded (-threaded -rtsopts -with-rtsopts=-N) then segfaults start to happen. It turns out that most API methods, including the deallocation methods take reference a common argument which is not thread-safe.
We successfully got rid of the segfaults by synchronizing all API calls including finalizers by locking on this argument.
Also, when compiling with -threaded -rtsopts -with-rtsopts=-N --copying-gc the segfaults disappear even without any locking. I searched and found the following sentence in the docs [3]:
Setting -N also has the effect of enabling the parallel garbage collector
I understand this as: -N implicitly adds --nonmoving-gc which runs concurrently with the program.
So finally my question: Is it enough to set --copying-gc to guarantee that our finalizers and other parts of the program never run concurrently? Are there any other options apart from this or locking?
GHC version: 8.10.4