Fwd: Safe TCP accept loop

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Fwd: Safe TCP accept loop

Sumit Raja
Hi,

I sent this to beginners but got no responses so I'm hoping someone
here can help. I’ve looked at
https://wiki.haskell.org/Concurrency_demos/Graceful_exit and used(2)
Using throwTo without the use of block and unblock. It runs on 8.2.1
with my limited testing. I can’t find out much about what the  > 7.x
GHC replacement for block/unblock is other than mask. What does the
unblock do in acceptConnections'?

Does this method of handling an accept loop still need masking of
async exceptions ? If so where does this need to be done?

I've got a version with async running for my specific application
(https://bitbucket.org/sumitraja/hvrr/src/6927216597a35a9a0d7f2e55cca83fa5b7279ee0/hvrr-comms/src/Network/VRR/Server/TCP/TCPAcceptLoop.hs)
but I don't know if I need to unmask at any point so was hoping for
some guidance.


Thanks



Sumit
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Safe TCP accept loop

Ömer Sinan Ağacan
Hi Sumit,

> Does this method of handling an accept loop still need masking of async
> exceptions

You need to mask async exceptions between `accept()` and cleanup action
registration, because an exception in between these operations will cause the
socket to leak.

You can take a look at warp's accept loop:

https://github.com/yesodweb/wai/blob/master/warp/Network/Wai/Handler/Warp/Run.hs#L211

Hope this helps,

Ömer

2017-10-24 2:08 GMT+03:00 Sumit Raja <[hidden email]>:

> Hi,
>
> I sent this to beginners but got no responses so I'm hoping someone
> here can help. I’ve looked at
> https://wiki.haskell.org/Concurrency_demos/Graceful_exit and used(2)
> Using throwTo without the use of block and unblock. It runs on 8.2.1
> with my limited testing. I can’t find out much about what the  > 7.x
> GHC replacement for block/unblock is other than mask. What does the
> unblock do in acceptConnections'?
>
> Does this method of handling an accept loop still need masking of
> async exceptions ? If so where does this need to be done?
>
> I've got a version with async running for my specific application
> (https://bitbucket.org/sumitraja/hvrr/src/6927216597a35a9a0d7f2e55cca83fa5b7279ee0/hvrr-comms/src/Network/VRR/Server/TCP/TCPAcceptLoop.hs)
> but I don't know if I need to unmask at any point so was hoping for
> some guidance.
>
>
> Thanks
>
>
>
> Sumit
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Safe TCP accept loop

Sumit Raja
Hi Ömer

> You need to mask async exceptions between `accept()` and cleanup action
> registration, because an exception in between these operations will cause the
> socket to leak.
>
> You can take a look at warp's accept loop:
>
> https://github.com/yesodweb/wai/blob/master/warp/Network/Wai/Handler/Warp/Run.hs#L211
>

Trying to map steps for the code you've pointed me to in bad pseudo code:

finally (mask >> acceptLoop serverSocket) (close serverSocket)

acceptLoop =
  unmask
  sock <- accept serverSock
  mask
    forkIO $ do
       mask
       finally (unmask >> process sock) (close sock)
  acceptLoop

Is this correct?

Thanks
Sumit
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Safe TCP accept loop

Ömer Sinan Ağacan
Your pseudo code doesn't look right although I couldn't completely understand
it. You need something like this:

  {-# LANGUAGE ScopedTypeVariables #-}

  import Network.Socket
  import Control.Concurrent
  import Control.Exception

  acceptLoop :: Socket -> IO ()
  acceptLoop sock =
      mask_ loop
    where
      loop = do
        -- only safe point in the loop for exceptions
        allowInterrupt

        (connected_sock, _) <- accept sock
        -- use forkIOWithUnmask: we want the thread to be
interruptable no matter
        -- what the inherited masking state is
        _thr_id <- forkIOWithUnmask (handle_conn connected_sock)

        loop

      handle_conn connected_sock unmask =
        -- register cleanup action, run the handler in interruptable state to be
        -- able to kill the thread.
        catch (unmask (handler connected_sock)) (\(_exc ::
SomeException) -> close connected_sock)

      handler connected_sock =
        -- fill here
        return ()


Ömer

2017-10-25 8:52 GMT+03:00 Sumit Raja <[hidden email]>:

> Hi Ömer
>
>> You need to mask async exceptions between `accept()` and cleanup action
>> registration, because an exception in between these operations will cause the
>> socket to leak.
>>
>> You can take a look at warp's accept loop:
>>
>> https://github.com/yesodweb/wai/blob/master/warp/Network/Wai/Handler/Warp/Run.hs#L211
>>
>
> Trying to map steps for the code you've pointed me to in bad pseudo code:
>
> finally (mask >> acceptLoop serverSocket) (close serverSocket)
>
> acceptLoop =
>   unmask
>   sock <- accept serverSock
>   mask
>     forkIO $ do
>        mask
>        finally (unmask >> process sock) (close sock)
>   acceptLoop
>
> Is this correct?
>
> Thanks
> Sumit
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Safe TCP accept loop

Sumit Raja
My apologies I've only just managed to get back to this. I've used
your method described above, thanks for the clear explanation

Now am unable to terminate the async thread that is running the accept
call. Seems to me that Warp relies on the termination of the main
thread to terminate the accept loop - is this correct?


On 25 October 2017 at 17:30, Ömer Sinan Ağacan <[hidden email]> wrote:

> Your pseudo code doesn't look right although I couldn't completely understand
> it. You need something like this:
>
>   {-# LANGUAGE ScopedTypeVariables #-}
>
>   import Network.Socket
>   import Control.Concurrent
>   import Control.Exception
>
>   acceptLoop :: Socket -> IO ()
>   acceptLoop sock =
>       mask_ loop
>     where
>       loop = do
>         -- only safe point in the loop for exceptions
>         allowInterrupt
>
>         (connected_sock, _) <- accept sock
>         -- use forkIOWithUnmask: we want the thread to be
> interruptable no matter
>         -- what the inherited masking state is
>         _thr_id <- forkIOWithUnmask (handle_conn connected_sock)
>
>         loop
>
>       handle_conn connected_sock unmask =
>         -- register cleanup action, run the handler in interruptable state to be
>         -- able to kill the thread.
>         catch (unmask (handler connected_sock)) (\(_exc ::
> SomeException) -> close connected_sock)
>
>       handler connected_sock =
>         -- fill here
>         return ()
>
>
> Ömer
>
> 2017-10-25 8:52 GMT+03:00 Sumit Raja <[hidden email]>:
>> Hi Ömer
>>
>>> You need to mask async exceptions between `accept()` and cleanup action
>>> registration, because an exception in between these operations will cause the
>>> socket to leak.
>>>
>>> You can take a look at warp's accept loop:
>>>
>>> https://github.com/yesodweb/wai/blob/master/warp/Network/Wai/Handler/Warp/Run.hs#L211
>>>
>>
>> Trying to map steps for the code you've pointed me to in bad pseudo code:
>>
>> finally (mask >> acceptLoop serverSocket) (close serverSocket)
>>
>> acceptLoop =
>>   unmask
>>   sock <- accept serverSock
>>   mask
>>     forkIO $ do
>>        mask
>>        finally (unmask >> process sock) (close sock)
>>   acceptLoop
>>
>> Is this correct?
>>
>> Thanks
>> Sumit
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.