11
11
module Network.Socket.Types (
12
12
-- * Socket type
13
13
Socket
14
- , fdSocket
15
14
, withFdSocket
15
+ , unsafeFdSocket
16
+ , touchFdSocket
17
+ , fdSocket
16
18
, mkSocket
17
19
, invalidateSocket
18
20
, close
@@ -94,6 +96,10 @@ instance Show Socket where
94
96
instance Eq Socket where
95
97
Socket ref1 _ == Socket ref2 _ = ref1 == ref2
96
98
99
+ {-# DEPRECATED fdSocket "Use withFdSocket or unsafeFdSocket instead" #-}
100
+ fdSocket :: Socket -> IO CInt
101
+ fdSocket = unsafeFdSocket
102
+
97
103
-- | Getting a file descriptor from a socket.
98
104
--
99
105
-- If a 'Socket' is shared with multiple threads and
@@ -111,37 +117,50 @@ instance Eq Socket where
111
117
-- 'System.Posix.IO.dup'. But this would still suffer from
112
118
-- a race condition between 'fdSocket' and 'close'.
113
119
--
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
+ --
114
124
-- 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, () ## )
118
142
119
143
-- | Get a file descriptor from a 'Socket'. The socket will never
120
144
-- be closed automatically before @withFdSocket@ completes, but
121
145
-- it may still be closed by an explicit call to 'close' or `close'`,
122
146
-- either before or during the call.
123
147
--
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.
126
151
--
127
152
-- Since: 3.1.0.0
128
153
withFdSocket :: Socket -> (CInt -> IO r ) -> IO r
129
- withFdSocket (Socket ref@ ( IORef ( STRef ref ## )) _) f = do
154
+ withFdSocket (Socket ref _) f = do
130
155
fd <- readIORef ref
131
156
-- Should we throw an exception if the socket is already invalid?
132
157
-- That will catch some mistakes but certainly not all.
133
158
134
159
r <- f fd
135
160
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
142
162
return r
143
163
144
-
145
164
-- | Creating a socket from a file descriptor.
146
165
mkSocket :: CInt -> IO Socket
147
166
mkSocket fd = do
0 commit comments