Skip to content

Commit d0557cf

Browse files
takano-akiokazu-yamamoto
authored andcommitted
Add unsafeFdSocket and touchSocket (Fixes #418)
1 parent 91fe934 commit d0557cf

File tree

2 files changed

+36
-15
lines changed

2 files changed

+36
-15
lines changed

Network/Socket.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,10 @@ module Network.Socket
136136
-- * Socket
137137
, Socket
138138
, socket
139-
, fdSocket
140139
, withFdSocket
140+
, unsafeFdSocket
141+
, touchFdSocket
142+
, fdSocket
141143
, mkSocket
142144
, socketToHandle
143145
-- ** Types of Socket

Network/Socket/Types.hsc

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
module Network.Socket.Types (
1212
-- * Socket type
1313
Socket
14-
, fdSocket
1514
, withFdSocket
15+
, unsafeFdSocket
16+
, touchFdSocket
17+
, fdSocket
1618
, mkSocket
1719
, invalidateSocket
1820
, close
@@ -94,6 +96,10 @@ instance Show Socket where
9496
instance Eq Socket where
9597
Socket ref1 _ == Socket ref2 _ = ref1 == ref2
9698

99+
{-# DEPRECATED fdSocket "Use withFdSocket or unsafeFdSocket instead" #-}
100+
fdSocket :: Socket -> IO CInt
101+
fdSocket = unsafeFdSocket
102+
97103
-- | Getting a file descriptor from a socket.
98104
--
99105
-- If a 'Socket' is shared with multiple threads and
@@ -111,37 +117,50 @@ instance Eq Socket where
111117
-- 'System.Posix.IO.dup'. But this would still suffer from
112118
-- a race condition between 'fdSocket' and 'close'.
113119
--
120+
-- If you use this function, you need to guarantee that the 'Socket' does not
121+
-- get garbage-collected until after you finish using the file descriptor.
122+
-- 'touchSocket' can be used for this purpose.
123+
--
114124
-- A safer option is to use 'withFdSocket' instead.
115-
{-# DEPRECATED fdSocket "Use withFdSocket instead" #-}
116-
fdSocket :: Socket -> IO CInt
117-
fdSocket (Socket ref _) = readIORef ref
125+
unsafeFdSocket :: Socket -> IO CInt
126+
unsafeFdSocket (Socket ref _) = readIORef ref
127+
128+
-- | Ensure that the given 'Socket' stays alive (i.e. not garbage-collected)
129+
-- at the given place in the sequence of IO actions. This function can be
130+
-- used in conjunction with 'unsafeFdSocket' to guarantee that the file
131+
-- descriptor is not prematurely freed.
132+
touchFdSocket :: Socket -> IO ()
133+
touchFdSocket (Socket ref _) = touch ref
134+
135+
touch :: IORef a -> IO ()
136+
touch (IORef (STRef mutVar)) =
137+
-- Thanks to a GHC issue, this touch# may not be quite guaranteed
138+
-- to work. There's talk of replacing the touch# primop with one
139+
-- that works better with the optimizer. But this seems to be the
140+
-- "right" way to do it for now.
141+
IO $ \s -> (## touch## mutVar s, () ##)
118142

119143
-- | Get a file descriptor from a 'Socket'. The socket will never
120144
-- be closed automatically before @withFdSocket@ completes, but
121145
-- it may still be closed by an explicit call to 'close' or `close'`,
122146
-- either before or during the call.
123147
--
124-
-- The file descriptor must not be used after @withFdSocket@ returns;
125-
-- see the documentation for 'fdSocket' to see why that is.
148+
-- The file descriptor must not be used after @withFdSocket@ returns, because
149+
-- the 'Socket' may have been garbage-collected, invalidating the file
150+
-- descriptor.
126151
--
127152
-- Since: 3.1.0.0
128153
withFdSocket :: Socket -> (CInt -> IO r) -> IO r
129-
withFdSocket (Socket ref@(IORef (STRef ref##)) _) f = do
154+
withFdSocket (Socket ref _) f = do
130155
fd <- readIORef ref
131156
-- Should we throw an exception if the socket is already invalid?
132157
-- That will catch some mistakes but certainly not all.
133158

134159
r <- f fd
135160

136-
-- Thanks to a GHC issue, this touch# may not be quite guaranteed
137-
-- to work. There's talk of replacing the touch# primop with one
138-
-- that works better with the optimizer. But this seems to be the
139-
-- "right" way to do it for now.
140-
141-
IO $ \s -> (## touch## ref## s, () ##)
161+
touch ref
142162
return r
143163

144-
145164
-- | Creating a socket from a file descriptor.
146165
mkSocket :: CInt -> IO Socket
147166
mkSocket fd = do

0 commit comments

Comments
 (0)