Concurrency control for GHC finalizers

Viewed 62

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

  1. https://github.com/IagoAbal/haskell-z3/issues/27
  2. https://hackage.haskell.org/package/base-4.14.0.0/docs/Foreign-Concurrent.html
  3. https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-concurrent.html#rts-flag--N
0 Answers
Related