2 issues and 1 proposal for runInUnboundThread

Hello, I found two small issues in Control.Concurrent: * Both runInBoundThread and runInUnboundThread use throw instead of throwIO. It's nicer to use throwIO in an IO context instead of throw because it guarantees ordering with respect to other IO actions. * runInUnboundThread explicitly checks the blocked status of the current thread which is redundant because mask also performs this check. I also have a new proposal: When you throw an asynchronous exception to a thread which is executing: `runInUnboundThread m`, m will keep executing and there's no way to kill it. I propose to catch asynchronous exceptions in runInUnboundThread and throw them to the thread which is executing m. m in turn can decide to catch or ignore them. In case m decides to ignore them or to rethrow them, the exception will be rethrown in the current thread: runInUnboundThread :: IO a -> IO a runInUnboundThread action = do bound <- isCurrentThreadBound if bound then do mv <- newEmptyMVar mask $ \restore -> do tid <- forkIO $ Exception.try (restore action) >>= putMVar mv let wait = takeMVar mv `Exception.catch` \(e :: SomeException) -> Exception.throwTo tid e >> wait wait >>= unsafeResult else action unsafeResult :: Either SomeException a -> IO a unsafeResult = either Exception.throwIO return The patch bundle attached to the ticket fixes the two issues and implements the above behavior. Discussion deadline: I don't think the fixes for the issues need discussion. They only need a review from one of the GHC devs. With regard to the proposal I propose a discussion deadline of 2 weeks from now: Thursday 28 October. Ticket: http://hackage.haskell.org/trac/ghc/ticket/4400 Regards, Bas

On Fri, Oct 15, 2010 at 12:00 AM, Bas van Dijk
When you throw an asynchronous exception to a thread which is executing: `runInUnboundThread m`, m will keep executing and there's no way to kill it.
I realize this isn't true. It's easy to kill 'm': import Control.Concurrent main = do mv <- newEmptyMVar let m = myThreadId >>= putMVar mv runInUnboundThread m takeMVar mv >>= killThread However I still believe my proposed version is better because I see `runInUnboundThread m` as just an optimized version of 'm'. In this perspective, `runInUnboundThread m` should behave as 'm' as much as possible. This means that asynchronous exception thrown to `runInUnboundThread m` should be thrown to 'm'. Bas

On 14/10/2010 23:00, Bas van Dijk wrote:
Hello,
I found two small issues in Control.Concurrent:
* Both runInBoundThread and runInUnboundThread use throw instead of throwIO. It's nicer to use throwIO in an IO context instead of throw because it guarantees ordering with respect to other IO actions.
* runInUnboundThread explicitly checks the blocked status of the current thread which is redundant because mask also performs this check.
I also have a new proposal:
When you throw an asynchronous exception to a thread which is executing: `runInUnboundThread m`, m will keep executing and there's no way to kill it.
I propose to catch asynchronous exceptions in runInUnboundThread and throw them to the thread which is executing m. m in turn can decide to catch or ignore them. In case m decides to ignore them or to rethrow them, the exception will be rethrown in the current thread:
runInUnboundThread :: IO a -> IO a runInUnboundThread action = do bound<- isCurrentThreadBound if bound then do mv<- newEmptyMVar mask $ \restore -> do tid<- forkIO $ Exception.try (restore action)>>= putMVar mv let wait = takeMVar mv `Exception.catch` \(e :: SomeException) -> Exception.throwTo tid e>> wait wait>>= unsafeResult else action
unsafeResult :: Either SomeException a -> IO a unsafeResult = either Exception.throwIO return
I think it's ok, no objections here. Do you have a use for runInUnboundThread, incidentally? Cheers, Simon

On Thu, Oct 21, 2010 at 11:29 AM, Simon Marlow
On 14/10/2010 23:00, Bas van Dijk wrote:
Hello,
I found two small issues in Control.Concurrent:
* Both runInBoundThread and runInUnboundThread use throw instead of throwIO. It's nicer to use throwIO in an IO context instead of throw because it guarantees ordering with respect to other IO actions.
* runInUnboundThread explicitly checks the blocked status of the current thread which is redundant because mask also performs this check.
I also have a new proposal:
When you throw an asynchronous exception to a thread which is executing: `runInUnboundThread m`, m will keep executing and there's no way to kill it.
I propose to catch asynchronous exceptions in runInUnboundThread and throw them to the thread which is executing m. m in turn can decide to catch or ignore them. In case m decides to ignore them or to rethrow them, the exception will be rethrown in the current thread:
runInUnboundThread :: IO a -> IO a runInUnboundThread action = do bound<- isCurrentThreadBound if bound then do mv<- newEmptyMVar mask $ \restore -> do tid<- forkIO $ Exception.try (restore action)>>= putMVar mv let wait = takeMVar mv `Exception.catch` \(e :: SomeException) -> Exception.throwTo tid e>> wait wait>>= unsafeResult else action
unsafeResult :: Either SomeException a -> IO a unsafeResult = either Exception.throwIO return
I think it's ok, no objections here. Do you have a use for runInUnboundThread, incidentally?
Not really. However I was planning to see if happstack-server could benefit from runInUnboundThread. Currently it forks threads in the main thread: http://patch-tag.com/r/mae/happstack/snapshot/current/content/pretty/happsta... Regards, Bas

On Fri, Oct 15, 2010 at 12:00 AM, Bas van Dijk
Hello,
I found two small issues in Control.Concurrent:
* Both runInBoundThread and runInUnboundThread use throw instead of throwIO. It's nicer to use throwIO in an IO context instead of throw because it guarantees ordering with respect to other IO actions.
* runInUnboundThread explicitly checks the blocked status of the current thread which is redundant because mask also performs this check.
I also have a new proposal:
When you throw an asynchronous exception to a thread which is executing: `runInUnboundThread m`, m will keep executing and there's no way to kill it.
I propose to catch asynchronous exceptions in runInUnboundThread and throw them to the thread which is executing m. m in turn can decide to catch or ignore them. In case m decides to ignore them or to rethrow them, the exception will be rethrown in the current thread:
runInUnboundThread :: IO a -> IO a runInUnboundThread action = do bound <- isCurrentThreadBound if bound then do mv <- newEmptyMVar mask $ \restore -> do tid <- forkIO $ Exception.try (restore action) >>= putMVar mv let wait = takeMVar mv `Exception.catch` \(e :: SomeException) -> Exception.throwTo tid e >> wait wait >>= unsafeResult else action
unsafeResult :: Either SomeException a -> IO a unsafeResult = either Exception.throwIO return
The patch bundle attached to the ticket fixes the two issues and implements the above behavior.
Discussion deadline:
I don't think the fixes for the issues need discussion. They only need a review from one of the GHC devs.
With regard to the proposal I propose a discussion deadline of 2 weeks from now: Thursday 28 October.
Ticket: http://hackage.haskell.org/trac/ghc/ticket/4400
Regards,
Bas
There're 2 days left for this proposal. Any more opinions? Thanks, Bas

On Tue, Oct 26, 2010 at 2:24 PM, Bas van Dijk
On Fri, Oct 15, 2010 at 12:00 AM, Bas van Dijk
wrote: Hello,
I found two small issues in Control.Concurrent:
* Both runInBoundThread and runInUnboundThread use throw instead of throwIO. It's nicer to use throwIO in an IO context instead of throw because it guarantees ordering with respect to other IO actions.
* runInUnboundThread explicitly checks the blocked status of the current thread which is redundant because mask also performs this check.
I also have a new proposal:
When you throw an asynchronous exception to a thread which is executing: `runInUnboundThread m`, m will keep executing and there's no way to kill it.
I propose to catch asynchronous exceptions in runInUnboundThread and throw them to the thread which is executing m. m in turn can decide to catch or ignore them. In case m decides to ignore them or to rethrow them, the exception will be rethrown in the current thread:
runInUnboundThread :: IO a -> IO a runInUnboundThread action = do bound <- isCurrentThreadBound if bound then do mv <- newEmptyMVar mask $ \restore -> do tid <- forkIO $ Exception.try (restore action) >>= putMVar mv let wait = takeMVar mv `Exception.catch` \(e :: SomeException) -> Exception.throwTo tid e >> wait wait >>= unsafeResult else action
unsafeResult :: Either SomeException a -> IO a unsafeResult = either Exception.throwIO return
The patch bundle attached to the ticket fixes the two issues and implements the above behavior.
Discussion deadline:
I don't think the fixes for the issues need discussion. They only need a review from one of the GHC devs.
With regard to the proposal I propose a discussion deadline of 2 weeks from now: Thursday 28 October.
Ticket: http://hackage.haskell.org/trac/ghc/ticket/4400
Regards,
Bas
There're 2 days left for this proposal. Any more opinions?
Thanks,
Bas
The deadline for this proposal has passed. There was little interest but no objections so I'm moving the ticket to 'patch'. Thanks, Bas
participants (2)
-
Bas van Dijk
-
Simon Marlow