Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make bracket safe from async exception?

Every Haskell article about exceptions repeats simple pattern: Use bracket function to allocate/release resources and you will be safe.

I have a concern, because I tested its behavior and detected that the thread can get async exception while working inside release section.

import Control.Exception
import Control.Concurrent

main = do
  tid <- forkIO myThread
  threadDelay 100000
  throwTo tid StackOverflow
  threadDelay 1000000

myThread = 
  bracket 
    (putStrLn "NEW")
    (\() -> threadDelay 500000 >> putStrLn "CLEAN")
    (\() -> putStrLn "USE")

In the snippet above "CLEAN" is not printed due async exception - so resource leaks! How it can be claimed safe?

I don't know everything it must be a reason. To make it safe as I see it I need to wrap every cleaning inside mask. It looks clumsy.

like image 736
Daniil Iaitskov Avatar asked Oct 21 '20 16:10

Daniil Iaitskov


1 Answers

To make it safe as I see it I need to wrap every cleaning inside mask.

Unfortunately, I think the answer is exactly that. If you have cleanup actions that must be run for resource safety, and you want to maintain resource safety with async exceptions, then you must use an uninterruptible mask during cleanup.

It’s similar to restricting yourself to signal-safe functions inside Unix/Linux signal handlers or exception-safe functions in C++ destructors, except the criterion here is “uninterruptible”, whether inherent to the functions you call, or by masking (maybe simpler to get right).

Alternatively, you can use the bracket from the unliftio package, which uses uninterruptible masking in its cleanup handler. (Unrelated to your question, this package provides the MonadUnliftIO class for lifting IO operations through stateless wrappers; it’s a restricted alternative to the more complex MonadBaseControl from monad-control, which handles stateful wrappers over any base monad.)

like image 197
Jon Purdy Avatar answered Oct 30 '22 06:10

Jon Purdy