OLD | NEW |
1 // Copyright 2013 The Go Authors. All rights reserved. | 1 // Copyright 2013 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // +build darwin linux | 5 // +build darwin linux |
6 | 6 |
7 package net | 7 package net |
8 | 8 |
9 #include "runtime.h" | 9 #include "runtime.h" |
10 #include "defs_GOOS_GOARCH.h" | 10 #include "defs_GOOS_GOARCH.h" |
(...skipping 29 matching lines...) Expand all Loading... |
40 { | 40 { |
41 Lock; | 41 Lock; |
42 PollDesc* first; | 42 PollDesc* first; |
43 // PollDesc objects must be type-stable, | 43 // PollDesc objects must be type-stable, |
44 // because we can get ready notification from epoll/kqueue | 44 // because we can get ready notification from epoll/kqueue |
45 // after the descriptor is closed/reused. | 45 // after the descriptor is closed/reused. |
46 // Stale notifications are detected using seq variable, | 46 // Stale notifications are detected using seq variable, |
47 // seq is incremented when deadlines are changed or descriptor is reused
. | 47 // seq is incremented when deadlines are changed or descriptor is reused
. |
48 } pollcache; | 48 } pollcache; |
49 | 49 |
50 static void» netpollblock(PollDesc*, int32); | 50 static bool» netpollblock(PollDesc*, int32); |
51 static G*» netpollunblock(PollDesc*, int32); | 51 static G*» netpollunblock(PollDesc*, int32, bool); |
52 static void deadline(int64, Eface); | 52 static void deadline(int64, Eface); |
53 static void readDeadline(int64, Eface); | 53 static void readDeadline(int64, Eface); |
54 static void writeDeadline(int64, Eface); | 54 static void writeDeadline(int64, Eface); |
55 static PollDesc* allocPollDesc(void); | 55 static PollDesc* allocPollDesc(void); |
56 static intgo checkerr(PollDesc *pd, int32 mode); | 56 static intgo checkerr(PollDesc *pd, int32 mode); |
57 | 57 |
58 static FuncVal deadlineFn = {(void(*)(void))deadline}; | 58 static FuncVal deadlineFn = {(void(*)(void))deadline}; |
59 static FuncVal readDeadlineFn = {(void(*)(void))readDeadline}; | 59 static FuncVal readDeadlineFn = {(void(*)(void))readDeadline}; |
60 static FuncVal writeDeadlineFn = {(void(*)(void))writeDeadline}; | 60 static FuncVal writeDeadlineFn = {(void(*)(void))writeDeadline}; |
61 | 61 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 pd->rg = nil; | 105 pd->rg = nil; |
106 else if(mode == 'w') | 106 else if(mode == 'w') |
107 pd->wg = nil; | 107 pd->wg = nil; |
108 ret: | 108 ret: |
109 runtime·unlock(pd); | 109 runtime·unlock(pd); |
110 } | 110 } |
111 | 111 |
112 func runtime_pollWait(pd *PollDesc, mode int) (err int) { | 112 func runtime_pollWait(pd *PollDesc, mode int) (err int) { |
113 runtime·lock(pd); | 113 runtime·lock(pd); |
114 err = checkerr(pd, mode); | 114 err = checkerr(pd, mode); |
115 » if(err) | 115 » if(err == 0) { |
116 » » goto ret; | 116 » » if(!netpollblock(pd, mode)) { |
117 » netpollblock(pd, mode); | 117 » » » err = checkerr(pd, mode); |
118 » err = checkerr(pd, mode); | 118 » » » if(err == 0) |
119 ret: | 119 » » » » runtime·throw("runtime_pollWait: unblocked by io
ready"); |
| 120 » » } |
| 121 » } |
120 runtime·unlock(pd); | 122 runtime·unlock(pd); |
121 } | 123 } |
122 | 124 |
| 125 func runtime_pollWaitCanceled(pd *PollDesc, mode int) { |
| 126 runtime·lock(pd); |
| 127 // wait for ioready, ignore closing or timeouts. |
| 128 while(!netpollblock(pd, mode)) |
| 129 ; |
| 130 runtime·unlock(pd); |
| 131 } |
| 132 |
123 func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) { | 133 func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) { |
124 runtime·lock(pd); | 134 runtime·lock(pd); |
125 if(pd->closing) | 135 if(pd->closing) |
126 goto ret; | 136 goto ret; |
127 pd->seq++; // invalidate current timers | 137 pd->seq++; // invalidate current timers |
128 // Reset current timers. | 138 // Reset current timers. |
129 if(pd->rt.fv) { | 139 if(pd->rt.fv) { |
130 runtime·deltimer(&pd->rt); | 140 runtime·deltimer(&pd->rt); |
131 pd->rt.fv = nil; | 141 pd->rt.fv = nil; |
132 } | 142 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 } | 182 } |
173 | 183 |
174 func runtime_pollUnblock(pd *PollDesc) { | 184 func runtime_pollUnblock(pd *PollDesc) { |
175 G *rg, *wg; | 185 G *rg, *wg; |
176 | 186 |
177 runtime·lock(pd); | 187 runtime·lock(pd); |
178 if(pd->closing) | 188 if(pd->closing) |
179 runtime·throw("runtime_pollUnblock: already closing"); | 189 runtime·throw("runtime_pollUnblock: already closing"); |
180 pd->closing = true; | 190 pd->closing = true; |
181 pd->seq++; | 191 pd->seq++; |
182 » rg = netpollunblock(pd, 'r'); | 192 » rg = netpollunblock(pd, 'r', false); |
183 » wg = netpollunblock(pd, 'w'); | 193 » wg = netpollunblock(pd, 'w', false); |
184 if(pd->rt.fv) { | 194 if(pd->rt.fv) { |
185 runtime·deltimer(&pd->rt); | 195 runtime·deltimer(&pd->rt); |
186 pd->rt.fv = nil; | 196 pd->rt.fv = nil; |
187 } | 197 } |
188 if(pd->wt.fv) { | 198 if(pd->wt.fv) { |
189 runtime·deltimer(&pd->wt); | 199 runtime·deltimer(&pd->wt); |
190 pd->wt.fv = nil; | 200 pd->wt.fv = nil; |
191 } | 201 } |
192 runtime·unlock(pd); | 202 runtime·unlock(pd); |
193 if(rg) | 203 if(rg) |
194 runtime·ready(rg); | 204 runtime·ready(rg); |
195 if(wg) | 205 if(wg) |
196 runtime·ready(wg); | 206 runtime·ready(wg); |
197 } | 207 } |
198 | 208 |
199 // make pd ready, newly runnable goroutines (if any) are enqueued info gpp list | 209 // make pd ready, newly runnable goroutines (if any) are enqueued info gpp list |
200 void | 210 void |
201 runtime·netpollready(G **gpp, PollDesc *pd, int32 mode) | 211 runtime·netpollready(G **gpp, PollDesc *pd, int32 mode) |
202 { | 212 { |
203 G *rg, *wg; | 213 G *rg, *wg; |
204 | 214 |
205 rg = wg = nil; | 215 rg = wg = nil; |
206 runtime·lock(pd); | 216 runtime·lock(pd); |
207 if(mode == 'r' || mode == 'r'+'w') | 217 if(mode == 'r' || mode == 'r'+'w') |
208 » » rg = netpollunblock(pd, 'r'); | 218 » » rg = netpollunblock(pd, 'r', true); |
209 if(mode == 'w' || mode == 'r'+'w') | 219 if(mode == 'w' || mode == 'r'+'w') |
210 » » wg = netpollunblock(pd, 'w'); | 220 » » wg = netpollunblock(pd, 'w', true); |
211 runtime·unlock(pd); | 221 runtime·unlock(pd); |
212 if(rg) { | 222 if(rg) { |
213 rg->schedlink = *gpp; | 223 rg->schedlink = *gpp; |
214 *gpp = rg; | 224 *gpp = rg; |
215 } | 225 } |
216 if(wg) { | 226 if(wg) { |
217 wg->schedlink = *gpp; | 227 wg->schedlink = *gpp; |
218 *gpp = wg; | 228 *gpp = wg; |
219 } | 229 } |
220 } | 230 } |
221 | 231 |
222 static intgo | 232 static intgo |
223 checkerr(PollDesc *pd, int32 mode) | 233 checkerr(PollDesc *pd, int32 mode) |
224 { | 234 { |
225 if(pd->closing) | 235 if(pd->closing) |
226 return 1; // errClosing | 236 return 1; // errClosing |
227 if((mode == 'r' && pd->rd < 0) || (mode == 'w' && pd->wd < 0)) | 237 if((mode == 'r' && pd->rd < 0) || (mode == 'w' && pd->wd < 0)) |
228 return 2; // errTimeout | 238 return 2; // errTimeout |
229 return 0; | 239 return 0; |
230 } | 240 } |
231 | 241 |
232 static void | 242 // returns true if IO is ready, or false if timedout or closed |
| 243 static bool |
233 netpollblock(PollDesc *pd, int32 mode) | 244 netpollblock(PollDesc *pd, int32 mode) |
234 { | 245 { |
235 G **gpp; | 246 G **gpp; |
236 | 247 |
237 gpp = &pd->rg; | 248 gpp = &pd->rg; |
238 if(mode == 'w') | 249 if(mode == 'w') |
239 gpp = &pd->wg; | 250 gpp = &pd->wg; |
240 if(*gpp == READY) { | 251 if(*gpp == READY) { |
241 *gpp = nil; | 252 *gpp = nil; |
242 » » return; | 253 » » return true; |
243 } | 254 } |
244 if(*gpp != nil) | 255 if(*gpp != nil) |
245 runtime·throw("epoll: double wait"); | 256 runtime·throw("epoll: double wait"); |
246 *gpp = g; | 257 *gpp = g; |
247 runtime·park(runtime·unlock, &pd->Lock, "IO wait"); | 258 runtime·park(runtime·unlock, &pd->Lock, "IO wait"); |
248 runtime·lock(pd); | 259 runtime·lock(pd); |
| 260 if(g->param) |
| 261 return true; |
| 262 return false; |
249 } | 263 } |
250 | 264 |
251 static G* | 265 static G* |
252 netpollunblock(PollDesc *pd, int32 mode) | 266 netpollunblock(PollDesc *pd, int32 mode, bool ioready) |
253 { | 267 { |
254 G **gpp, *old; | 268 G **gpp, *old; |
255 | 269 |
256 gpp = &pd->rg; | 270 gpp = &pd->rg; |
257 if(mode == 'w') | 271 if(mode == 'w') |
258 gpp = &pd->wg; | 272 gpp = &pd->wg; |
259 if(*gpp == READY) | 273 if(*gpp == READY) |
260 return nil; | 274 return nil; |
261 if(*gpp == nil) { | 275 if(*gpp == nil) { |
262 » » *gpp = READY; | 276 » » // Only set READY for ioready. runtime_pollWait |
| 277 » » // will check for timeout/cancel before waiting. |
| 278 » » if(ioready) |
| 279 » » » *gpp = READY; |
263 return nil; | 280 return nil; |
264 } | 281 } |
265 old = *gpp; | 282 old = *gpp; |
| 283 // pass unblock reason onto blocked g |
| 284 old->param = (void*)ioready; |
266 *gpp = nil; | 285 *gpp = nil; |
267 return old; | 286 return old; |
268 } | 287 } |
269 | 288 |
270 static void | 289 static void |
271 deadlineimpl(int64 now, Eface arg, bool read, bool write) | 290 deadlineimpl(int64 now, Eface arg, bool read, bool write) |
272 { | 291 { |
273 PollDesc *pd; | 292 PollDesc *pd; |
274 uint32 seq; | 293 uint32 seq; |
275 G *rg, *wg; | 294 G *rg, *wg; |
276 | 295 |
277 USED(now); | 296 USED(now); |
278 pd = (PollDesc*)arg.data; | 297 pd = (PollDesc*)arg.data; |
279 // This is the seq when the timer was set. | 298 // This is the seq when the timer was set. |
280 // If it's stale, ignore the timer event. | 299 // If it's stale, ignore the timer event. |
281 seq = (uintptr)arg.type; | 300 seq = (uintptr)arg.type; |
282 rg = wg = nil; | 301 rg = wg = nil; |
283 runtime·lock(pd); | 302 runtime·lock(pd); |
284 if(seq != pd->seq) { | 303 if(seq != pd->seq) { |
285 // The descriptor was reused or timers were reset. | 304 // The descriptor was reused or timers were reset. |
286 runtime·unlock(pd); | 305 runtime·unlock(pd); |
287 return; | 306 return; |
288 } | 307 } |
289 if(read) { | 308 if(read) { |
290 if(pd->rd <= 0 || pd->rt.fv == nil) | 309 if(pd->rd <= 0 || pd->rt.fv == nil) |
291 runtime·throw("deadlineimpl: inconsistent read deadline"
); | 310 runtime·throw("deadlineimpl: inconsistent read deadline"
); |
292 pd->rd = -1; | 311 pd->rd = -1; |
293 pd->rt.fv = nil; | 312 pd->rt.fv = nil; |
294 » » rg = netpollunblock(pd, 'r'); | 313 » » rg = netpollunblock(pd, 'r', false); |
295 } | 314 } |
296 if(write) { | 315 if(write) { |
297 if(pd->wd <= 0 || (pd->wt.fv == nil && !read)) | 316 if(pd->wd <= 0 || (pd->wt.fv == nil && !read)) |
298 runtime·throw("deadlineimpl: inconsistent write deadline
"); | 317 runtime·throw("deadlineimpl: inconsistent write deadline
"); |
299 pd->wd = -1; | 318 pd->wd = -1; |
300 pd->wt.fv = nil; | 319 pd->wt.fv = nil; |
301 » » wg = netpollunblock(pd, 'w'); | 320 » » wg = netpollunblock(pd, 'w', false); |
302 } | 321 } |
303 runtime·unlock(pd); | 322 runtime·unlock(pd); |
304 if(rg) | 323 if(rg) |
305 runtime·ready(rg); | 324 runtime·ready(rg); |
306 if(wg) | 325 if(wg) |
307 runtime·ready(wg); | 326 runtime·ready(wg); |
308 } | 327 } |
309 | 328 |
310 static void | 329 static void |
311 deadline(int64 now, Eface arg) | 330 deadline(int64 now, Eface arg) |
(...skipping 30 matching lines...) Expand all Loading... |
342 for(i = 0; i < n; i++) { | 361 for(i = 0; i < n; i++) { |
343 pd[i].link = pollcache.first; | 362 pd[i].link = pollcache.first; |
344 pollcache.first = &pd[i]; | 363 pollcache.first = &pd[i]; |
345 } | 364 } |
346 } | 365 } |
347 pd = pollcache.first; | 366 pd = pollcache.first; |
348 pollcache.first = pd->link; | 367 pollcache.first = pd->link; |
349 runtime·unlock(&pollcache); | 368 runtime·unlock(&pollcache); |
350 return pd; | 369 return pd; |
351 } | 370 } |
OLD | NEW |