LEFT | RIGHT |
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 windows | 5 // +build darwin linux windows |
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 |
123 func runtime_pollWaitCanceled(pd *PollDesc, mode int) { | 125 func runtime_pollWaitCanceled(pd *PollDesc, mode int) { |
124 runtime·lock(pd); | 126 runtime·lock(pd); |
125 » netpollblock(pd, mode); | 127 » // wait for ioready, ignore closing or timeouts. |
| 128 » while(!netpollblock(pd, mode)) |
| 129 » » ; |
126 runtime·unlock(pd); | 130 runtime·unlock(pd); |
127 } | 131 } |
128 | 132 |
129 func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) { | 133 func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) { |
130 runtime·lock(pd); | 134 runtime·lock(pd); |
131 if(pd->closing) | 135 if(pd->closing) |
132 goto ret; | 136 goto ret; |
133 pd->seq++; // invalidate current timers | 137 pd->seq++; // invalidate current timers |
134 // Reset current timers. | 138 // Reset current timers. |
135 if(pd->rt.fv) { | 139 if(pd->rt.fv) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 } | 182 } |
179 | 183 |
180 func runtime_pollUnblock(pd *PollDesc) { | 184 func runtime_pollUnblock(pd *PollDesc) { |
181 G *rg, *wg; | 185 G *rg, *wg; |
182 | 186 |
183 runtime·lock(pd); | 187 runtime·lock(pd); |
184 if(pd->closing) | 188 if(pd->closing) |
185 runtime·throw("runtime_pollUnblock: already closing"); | 189 runtime·throw("runtime_pollUnblock: already closing"); |
186 pd->closing = true; | 190 pd->closing = true; |
187 pd->seq++; | 191 pd->seq++; |
188 » rg = netpollunblock(pd, 'r'); | 192 » rg = netpollunblock(pd, 'r', false); |
189 » wg = netpollunblock(pd, 'w'); | 193 » wg = netpollunblock(pd, 'w', false); |
190 if(pd->rt.fv) { | 194 if(pd->rt.fv) { |
191 runtime·deltimer(&pd->rt); | 195 runtime·deltimer(&pd->rt); |
192 pd->rt.fv = nil; | 196 pd->rt.fv = nil; |
193 } | 197 } |
194 if(pd->wt.fv) { | 198 if(pd->wt.fv) { |
195 runtime·deltimer(&pd->wt); | 199 runtime·deltimer(&pd->wt); |
196 pd->wt.fv = nil; | 200 pd->wt.fv = nil; |
197 } | 201 } |
198 runtime·unlock(pd); | 202 runtime·unlock(pd); |
199 if(rg) | 203 if(rg) |
200 runtime·ready(rg); | 204 runtime·ready(rg); |
201 if(wg) | 205 if(wg) |
202 runtime·ready(wg); | 206 runtime·ready(wg); |
203 } | 207 } |
204 | 208 |
205 // 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 |
206 void | 210 void |
207 runtime·netpollready(G **gpp, PollDesc *pd, int32 mode) | 211 runtime·netpollready(G **gpp, PollDesc *pd, int32 mode) |
208 { | 212 { |
209 G *rg, *wg; | 213 G *rg, *wg; |
210 | 214 |
211 rg = wg = nil; | 215 rg = wg = nil; |
212 runtime·lock(pd); | 216 runtime·lock(pd); |
213 if(mode == 'r' || mode == 'r'+'w') | 217 if(mode == 'r' || mode == 'r'+'w') |
214 » » rg = netpollunblock(pd, 'r'); | 218 » » rg = netpollunblock(pd, 'r', true); |
215 if(mode == 'w' || mode == 'r'+'w') | 219 if(mode == 'w' || mode == 'r'+'w') |
216 » » wg = netpollunblock(pd, 'w'); | 220 » » wg = netpollunblock(pd, 'w', true); |
217 runtime·unlock(pd); | 221 runtime·unlock(pd); |
218 if(rg) { | 222 if(rg) { |
219 rg->schedlink = *gpp; | 223 rg->schedlink = *gpp; |
220 *gpp = rg; | 224 *gpp = rg; |
221 } | 225 } |
222 if(wg) { | 226 if(wg) { |
223 wg->schedlink = *gpp; | 227 wg->schedlink = *gpp; |
224 *gpp = wg; | 228 *gpp = wg; |
225 } | 229 } |
226 } | 230 } |
227 | 231 |
228 static intgo | 232 static intgo |
229 checkerr(PollDesc *pd, int32 mode) | 233 checkerr(PollDesc *pd, int32 mode) |
230 { | 234 { |
231 if(pd->closing) | 235 if(pd->closing) |
232 return 1; // errClosing | 236 return 1; // errClosing |
233 if((mode == 'r' && pd->rd < 0) || (mode == 'w' && pd->wd < 0)) | 237 if((mode == 'r' && pd->rd < 0) || (mode == 'w' && pd->wd < 0)) |
234 return 2; // errTimeout | 238 return 2; // errTimeout |
235 return 0; | 239 return 0; |
236 } | 240 } |
237 | 241 |
238 static void | 242 // returns true if IO is ready, or false if timedout or closed |
| 243 static bool |
239 netpollblock(PollDesc *pd, int32 mode) | 244 netpollblock(PollDesc *pd, int32 mode) |
240 { | 245 { |
241 G **gpp; | 246 G **gpp; |
242 | 247 |
243 gpp = &pd->rg; | 248 gpp = &pd->rg; |
244 if(mode == 'w') | 249 if(mode == 'w') |
245 gpp = &pd->wg; | 250 gpp = &pd->wg; |
246 if(*gpp == READY) { | 251 if(*gpp == READY) { |
247 *gpp = nil; | 252 *gpp = nil; |
248 » » return; | 253 » » return true; |
249 } | 254 } |
250 if(*gpp != nil) | 255 if(*gpp != nil) |
251 runtime·throw("epoll: double wait"); | 256 runtime·throw("epoll: double wait"); |
252 *gpp = g; | 257 *gpp = g; |
253 runtime·park(runtime·unlock, &pd->Lock, "IO wait"); | 258 runtime·park(runtime·unlock, &pd->Lock, "IO wait"); |
254 runtime·lock(pd); | 259 runtime·lock(pd); |
| 260 if(g->param) |
| 261 return true; |
| 262 return false; |
255 } | 263 } |
256 | 264 |
257 static G* | 265 static G* |
258 netpollunblock(PollDesc *pd, int32 mode) | 266 netpollunblock(PollDesc *pd, int32 mode, bool ioready) |
259 { | 267 { |
260 G **gpp, *old; | 268 G **gpp, *old; |
261 | 269 |
262 gpp = &pd->rg; | 270 gpp = &pd->rg; |
263 if(mode == 'w') | 271 if(mode == 'w') |
264 gpp = &pd->wg; | 272 gpp = &pd->wg; |
265 if(*gpp == READY) | 273 if(*gpp == READY) |
266 return nil; | 274 return nil; |
267 if(*gpp == nil) { | 275 if(*gpp == nil) { |
268 » » *gpp = READY; | 276 » » // Only set READY for ioready. runtime_pollWait |
| 277 » » // will check for timeout/cancel before waiting. |
| 278 » » if(ioready) |
| 279 » » » *gpp = READY; |
269 return nil; | 280 return nil; |
270 } | 281 } |
271 old = *gpp; | 282 old = *gpp; |
| 283 // pass unblock reason onto blocked g |
| 284 old->param = (void*)ioready; |
272 *gpp = nil; | 285 *gpp = nil; |
273 return old; | 286 return old; |
274 } | 287 } |
275 | 288 |
276 static void | 289 static void |
277 deadlineimpl(int64 now, Eface arg, bool read, bool write) | 290 deadlineimpl(int64 now, Eface arg, bool read, bool write) |
278 { | 291 { |
279 PollDesc *pd; | 292 PollDesc *pd; |
280 uint32 seq; | 293 uint32 seq; |
281 G *rg, *wg; | 294 G *rg, *wg; |
282 | 295 |
283 USED(now); | 296 USED(now); |
284 pd = (PollDesc*)arg.data; | 297 pd = (PollDesc*)arg.data; |
285 // This is the seq when the timer was set. | 298 // This is the seq when the timer was set. |
286 // If it's stale, ignore the timer event. | 299 // If it's stale, ignore the timer event. |
287 seq = (uintptr)arg.type; | 300 seq = (uintptr)arg.type; |
288 rg = wg = nil; | 301 rg = wg = nil; |
289 runtime·lock(pd); | 302 runtime·lock(pd); |
290 if(seq != pd->seq) { | 303 if(seq != pd->seq) { |
291 // The descriptor was reused or timers were reset. | 304 // The descriptor was reused or timers were reset. |
292 runtime·unlock(pd); | 305 runtime·unlock(pd); |
293 return; | 306 return; |
294 } | 307 } |
295 if(read) { | 308 if(read) { |
296 if(pd->rd <= 0 || pd->rt.fv == nil) | 309 if(pd->rd <= 0 || pd->rt.fv == nil) |
297 runtime·throw("deadlineimpl: inconsistent read deadline"
); | 310 runtime·throw("deadlineimpl: inconsistent read deadline"
); |
298 pd->rd = -1; | 311 pd->rd = -1; |
299 pd->rt.fv = nil; | 312 pd->rt.fv = nil; |
300 » » rg = netpollunblock(pd, 'r'); | 313 » » rg = netpollunblock(pd, 'r', false); |
301 } | 314 } |
302 if(write) { | 315 if(write) { |
303 if(pd->wd <= 0 || (pd->wt.fv == nil && !read)) | 316 if(pd->wd <= 0 || (pd->wt.fv == nil && !read)) |
304 runtime·throw("deadlineimpl: inconsistent write deadline
"); | 317 runtime·throw("deadlineimpl: inconsistent write deadline
"); |
305 pd->wd = -1; | 318 pd->wd = -1; |
306 pd->wt.fv = nil; | 319 pd->wt.fv = nil; |
307 » » wg = netpollunblock(pd, 'w'); | 320 » » wg = netpollunblock(pd, 'w', false); |
308 } | 321 } |
309 runtime·unlock(pd); | 322 runtime·unlock(pd); |
310 if(rg) | 323 if(rg) |
311 runtime·ready(rg); | 324 runtime·ready(rg); |
312 if(wg) | 325 if(wg) |
313 runtime·ready(wg); | 326 runtime·ready(wg); |
314 } | 327 } |
315 | 328 |
316 static void | 329 static void |
317 deadline(int64 now, Eface arg) | 330 deadline(int64 now, Eface arg) |
(...skipping 19 matching lines...) Expand all Loading... |
337 PollDesc *pd; | 350 PollDesc *pd; |
338 uint32 i, n; | 351 uint32 i, n; |
339 | 352 |
340 runtime·lock(&pollcache); | 353 runtime·lock(&pollcache); |
341 if(pollcache.first == nil) { | 354 if(pollcache.first == nil) { |
342 n = PageSize/sizeof(*pd); | 355 n = PageSize/sizeof(*pd); |
343 if(n == 0) | 356 if(n == 0) |
344 n = 1; | 357 n = 1; |
345 // Must be in non-GC memory because can be referenced | 358 // Must be in non-GC memory because can be referenced |
346 // only from epoll/kqueue internals. | 359 // only from epoll/kqueue internals. |
347 » » pd = runtime·SysAlloc(n*sizeof(*pd)); | 360 » » pd = runtime·persistentalloc(n*sizeof(*pd), 0); |
348 for(i = 0; i < n; i++) { | 361 for(i = 0; i < n; i++) { |
349 pd[i].link = pollcache.first; | 362 pd[i].link = pollcache.first; |
350 pollcache.first = &pd[i]; | 363 pollcache.first = &pd[i]; |
351 } | 364 } |
352 } | 365 } |
353 pd = pollcache.first; | 366 pd = pollcache.first; |
354 pollcache.first = pd->link; | 367 pollcache.first = pd->link; |
355 runtime·unlock(&pollcache); | 368 runtime·unlock(&pollcache); |
356 return pd; | 369 return pd; |
357 } | 370 } |
LEFT | RIGHT |