# Determining whether the RTS has shut down

**URL:** <https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540>\
**Category:** Learn\
**Created:** [July 22, 2025, 10:02pm UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540 "2025-07-22T22:02:45Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ppelleti](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ppelleti/32/2999_2.png) [@ppelleti](https://discourse.haskell.org/u/ppelleti)\
**Post date:** [July 22, 2025, 10:02pm UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/1 "2025-07-22T22:02:45Z")

</div>

I have a C thread which is running in the background, and it makes calls to Haskell code periodically (for logging). Is there a way for the C code to check whether the RTS has started to shut down? I don’t want to crash if the C thread is still logging while the Haskell program is exiting. And I would prefer to do this without having to wrap the Haskell program in `bracket` or similar.

I asked ChatGPT, and it hallucinated the existence of a function `hs_set_exit_hook()` in GHC 9.2.1 and later. However, as near as I can tell, this function does not exist in any version of GHC, and has never been mentioned anywhere outside of an AI fever dream.

---

<div class="post-metadata">

**Author:** ![eldritch-cookie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/eldritch-cookie/32/4130_2.png) [@eldritch-cookie](https://discourse.haskell.org/u/eldritch-cookie)\
**Post date:** [July 23, 2025, 11:58am UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/2 "2025-07-23T11:58:00Z")

</div>

who is shutting down the haskell RTS? the same thread responsible for calling hs\_init should call hs\_exit, and set some way to signal to other c threads that they can’t call haskell functions.

---

<div class="post-metadata">

**Author:** ![ppelleti](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ppelleti/32/2999_2.png) [@ppelleti](https://discourse.haskell.org/u/ppelleti)\
**Post date:** [July 23, 2025, 1:35pm UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/3 "2025-07-23T13:35:31Z")

</div>

The scenario is that I’m writing a Haskell library which wraps an existing C library. It’s possible to pass callback functions to the C library, which in turn would then call back into Haskell.

Most likely, there would just be a Haskell `main` and not a C `main()`, so `hs_init()` and `hs_exit()` would be called by whatever `main()` the compiler generates automatically. If there is an explicit C `main()`, it would not be under my control.

When I said I didn’t want to wrap the program in `bracket`, what I meant more generally is that I don’t want to require a user of the library to do something special in `main`, whether that’s a Haskell `main` or a C `main()`.

---

<div class="post-metadata">

**Author:** ![eldritch-cookie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/eldritch-cookie/32/4130_2.png) [@eldritch-cookie](https://discourse.haskell.org/u/eldritch-cookie)\
**Post date:** [July 24, 2025, 1:24pm UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/4 "2025-07-24T13:24:32Z")

</div>

is the c thread spawned directly from haskell? is the FunPtr Allocated by the user or the library? assuming your library exposes a (IO a) function, and the FunPtr is allocated by your library just keep count of every funPtr Allocated and wait until the C thread exits to deallocate everything and exit, ie forever $ wait5minforCThread fptrIORef …  
if the user has control of when to allocate/free the FunPtr it is probably impossible to not require that they do some special logic in main.  
although i think it is possible to escape IORef/MVars/TVars you will then most likely need to use the ContT monad transformer to pretend that callbacks return the value

---

<div class="post-metadata">

**Author:** ![eldritch-cookie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/eldritch-cookie/32/4130_2.png) [@eldritch-cookie](https://discourse.haskell.org/u/eldritch-cookie)\
**Post date:** [July 24, 2025, 1:47pm UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/5 "2025-07-24T13:47:29Z")

</div>

> **[Haskell Playground](https://play.haskell.org/saved/lUzLtwJ5)**

Proof you can do it without IORefs, not that you should, use TVars liberally but no global state!!!

---

<div class="post-metadata">

**Author:** ![simon](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/simon/32/3292_2.png) [@simon](https://discourse.haskell.org/u/simon)\
**Post date:** [July 24, 2025, 3:15pm UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/6 "2025-07-24T15:15:56Z")

</div>

I do not understand exactly what you are trying to achieve. I am assuming you have some function `startBackgroundThreadInC :: (SomeType -> IO ()) -> IO ()` which takes a Haskell callback and runs in the background for some time.

This is problematic whether your background task runs in Haskell or in C. You need to make sure that your main thread waits for your background tasks to finish, either by waiting or killing them.

In your case, the `with` pattern seems to me like the obvious solution:

```haskell
withCThread :: (SomeType -> IO ()) -> IO a -> IO a
withCThread callback program = bracket (startBackgroundThreadInC callback) waitCThread (const program)

```

The use of `bracket` is hidden, though I am not sure if this is the interface you want.

If you have multiple functions which interact with the C library in such a callback manner, then you can also try to generalize, ensuring that the C library properly shuts down:

```haskell
data CLibraryLifetime = CLibraryLifetime

withCThread :: (CLibraryLifetime -> IO a) -> IO a
withCThread program = bracket setupCLibrary waitCThread (const $ program CLibraryLifetime)

startBackgroundThreadInC :: CLibraryLifetime -> (SomeType -> IO ()) -> IO ()
startBackgroundThreadInC _ callback = ...

```

---

<div class="post-metadata">

**Author:** ![jackdk](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@jackdk](https://discourse.haskell.org/u/jackdk)\
**Post date:** [July 24, 2025, 10:08pm UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/7 "2025-07-24T22:08:07Z")

</div>

I like that `with`-style function that controls the library’s init/shutdown lifecycle, especially since you can make it exception-safe. You can also do a `runST`-style trick to ensure that library-provided resources cannot escape the `with`.

Here’s a recent post about that sort of thing: [Bluefin prevents handles leaking - #5 by MangoIV](https://discourse.haskell.org/t/bluefin-prevents-handles-leaking/10627/5)

---

<div class="post-metadata">

**Author:** ![ppelleti](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ppelleti/32/2999_2.png) [@ppelleti](https://discourse.haskell.org/u/ppelleti)\
**Post date:** [July 26, 2025, 3:55am UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/8 "2025-07-26T03:55:35Z")

</div>

The thing that makes it awkward is that the C library I’m wrapping doesn’t have explicit init/shutdown functions. It just auto-initializes on first use. So it doesn’t match up well with the Haskell `with` idiom.

---

<div class="post-metadata">

**Author:** ![simon](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/simon/32/3292_2.png) [@simon](https://discourse.haskell.org/u/simon)\
**Post date:** [July 26, 2025, 10:32am UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/9 "2025-07-26T10:32:43Z")

</div>

Using the `with` pattern does not actually mean that you have to initialize something. From a user perspective, `with` denotes a scope where you can safely use the C library. As a library author, you can make sure that users run the cleanup code.

Maybe something like this is what you are looking for:

```haskell
useCLibrary :: IO () -> IO ()
useCLibrary action = action `finally` myCustomExitHook

-- then:
main :: IO ()
main = useCLibrary $ do
  ... program from the user

```

This comes close to the imaginary `hs_set_exit_hook` with minimal setup in `main`. However, I think this might be exactly what you wanted to avoid. Still, I cannot really think of a way which does this completely automatically, not requiring any setup in the `main` function.

---

<div class="post-metadata">

**Author:** ![ppelleti](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ppelleti/32/2999_2.png) [@ppelleti](https://discourse.haskell.org/u/ppelleti)\
**Post date:** [July 26, 2025, 11:44pm UTC](https://discourse.haskell.org/t/determining-whether-the-rts-has-shut-down/12540/10 "2025-07-26T23:44:41Z")

</div>

OK, thanks! Yes, that is exactly what I was trying to avoid. But it looks like there isn’t really a way to do what I actually want to do (determine what state the RTS is in), so I’m going to have to rethink things a bit. I appreciate the information, though.
