1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
14 // Map gccgo field names to gc field names.
15 // Eface aka __go_empty_interface.
16 #define type __type_descriptor
19 // Integrated network poller (platform-independent part).
20 // A particular implementation (epoll/kqueue) must define the following functions:
21 // void runtime_netpollinit(void); // to initialize the poller
22 // int32 runtime_netpollopen(uintptr fd, PollDesc *pd); // to arm edge-triggered notifications
23 // and associate fd with pd.
24 // An implementation must call the following function to denote that the pd is ready.
25 // void runtime_netpollready(G **gpp, PollDesc *pd, int32 mode);
27 // PollDesc contains 2 binary semaphores, rg and wg, to park reader and writer
28 // goroutines respectively. The semaphore can be in the following states:
29 // READY - io readiness notification is pending;
30 // a goroutine consumes the notification by changing the state to nil.
31 // WAIT - a goroutine prepares to park on the semaphore, but not yet parked;
32 // the goroutine commits to park by changing the state to G pointer,
33 // or, alternatively, concurrent io notification changes the state to READY,
34 // or, alternatively, concurrent timeout/close changes the state to nil.
35 // G pointer - the goroutine is blocked on the semaphore;
36 // io notification or timeout/close changes the state to READY or nil respectively
37 // and unparks the goroutine.
38 // nil - nothing of the above.
44 PollBlockSize = 4*1024,
49 PollDesc* link; // in pollcache, protected by pollcache.Lock
51 // The lock protects pollOpen, pollSetDeadline, pollUnblock and deadlineimpl operations.
52 // This fully covers seq, rt and wt variables. fd is constant throughout the PollDesc lifetime.
53 // pollReset, pollWait, pollWaitCanceled and runtime_netpollready (IO rediness notification)
54 // proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
55 // in a lock-free way by all operations.
56 Lock; // protectes the following fields
59 uintptr seq; // protects from stale timers and ready notifications
60 G* rg; // READY, WAIT, G waiting for read or nil
61 Timer rt; // read deadline timer (set if rt.fv != nil)
62 int64 rd; // read deadline
63 G* wg; // READY, WAIT, G waiting for write or nil
64 Timer wt; // write deadline timer
65 int64 wd; // write deadline
66 void* user; // user settable cookie
73 // PollDesc objects must be type-stable,
74 // because we can get ready notification from epoll/kqueue
75 // after the descriptor is closed/reused.
76 // Stale notifications are detected using seq variable,
77 // seq is incremented when deadlines are changed or descriptor is reused.
80 static bool netpollblock(PollDesc*, int32, bool);
81 static G* netpollunblock(PollDesc*, int32, bool);
82 static void deadline(Eface, uintptr);
83 static void readDeadline(Eface, uintptr);
84 static void writeDeadline(Eface, uintptr);
85 static PollDesc* allocPollDesc(void);
86 static intgo checkerr(PollDesc *pd, int32 mode);
88 static FuncVal deadlineFn = {(void(*)(void))deadline};
89 static FuncVal readDeadlineFn = {(void(*)(void))readDeadline};
90 static FuncVal writeDeadlineFn = {(void(*)(void))writeDeadline};
92 // runtimeNano returns the current value of the runtime clock in nanoseconds.
93 func runtimeNano() (ns int64) {
94 ns = runtime_nanotime();
97 func runtime_pollServerInit() {
98 runtime_netpollinit();
101 func runtime_pollOpen(fd uintptr) (pd *PollDesc, errno int) {
102 pd = allocPollDesc();
104 if(pd->wg != nil && pd->wg != READY)
105 runtime_throw("runtime_pollOpen: blocked write on free descriptor");
106 if(pd->rg != nil && pd->rg != READY)
107 runtime_throw("runtime_pollOpen: blocked read on free descriptor");
117 errno = runtime_netpollopen(fd, pd);
120 func runtime_pollClose(pd *PollDesc) {
122 runtime_throw("runtime_pollClose: close w/o unblock");
123 if(pd->wg != nil && pd->wg != READY)
124 runtime_throw("runtime_pollClose: blocked write on closing descriptor");
125 if(pd->rg != nil && pd->rg != READY)
126 runtime_throw("runtime_pollClose: blocked read on closing descriptor");
127 runtime_netpollclose(pd->fd);
128 runtime_lock(&pollcache);
129 pd->link = pollcache.first;
130 pollcache.first = pd;
131 runtime_unlock(&pollcache);
134 func runtime_pollReset(pd *PollDesc, mode int) (err int) {
135 err = checkerr(pd, mode);
145 func runtime_pollWait(pd *PollDesc, mode int) (err int) {
146 err = checkerr(pd, mode);
148 // As for now only Solaris uses level-triggered IO.
150 runtime_netpollarm(pd, mode);
151 while(!netpollblock(pd, mode, false)) {
152 err = checkerr(pd, mode);
155 // Can happen if timeout has fired and unblocked us,
156 // but before we had a chance to run, timeout has been reset.
157 // Pretend it has not happened and retry.
162 func runtime_pollWaitCanceled(pd *PollDesc, mode int) {
163 // This function is used only on windows after a failed attempt to cancel
164 // a pending async IO operation. Wait for ioready, ignore closing or timeouts.
165 while(!netpollblock(pd, mode, true))
169 func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
177 pd->seq++; // invalidate current timers
178 // Reset current timers.
180 runtime_deltimer(&pd->rt);
184 runtime_deltimer(&pd->wt);
188 if(d != 0 && d <= runtime_nanotime())
190 if(mode == 'r' || mode == 'r'+'w')
192 if(mode == 'w' || mode == 'r'+'w')
194 if(pd->rd > 0 && pd->rd == pd->wd) {
195 pd->rt.fv = &deadlineFn;
196 pd->rt.when = pd->rd;
197 // Copy current seq into the timer arg.
198 // Timer func will check the seq against current descriptor seq,
199 // if they differ the descriptor was reused or timers were reset.
200 pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
201 pd->rt.arg.data = pd;
202 pd->rt.seq = pd->seq;
203 runtime_addtimer(&pd->rt);
206 pd->rt.fv = &readDeadlineFn;
207 pd->rt.when = pd->rd;
208 pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
209 pd->rt.arg.data = pd;
210 pd->rt.seq = pd->seq;
211 runtime_addtimer(&pd->rt);
214 pd->wt.fv = &writeDeadlineFn;
215 pd->wt.when = pd->wd;
216 pd->wt.arg.type = nil; // should be *pollDesc type descriptor.
217 pd->wt.arg.data = pd;
218 pd->wt.seq = pd->seq;
219 runtime_addtimer(&pd->wt);
222 // If we set the new deadline in the past, unblock currently pending IO if any.
224 runtime_atomicstorep(&wg, nil); // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
226 rg = netpollunblock(pd, 'r', false);
228 wg = netpollunblock(pd, 'w', false);
236 func runtime_pollUnblock(pd *PollDesc) {
241 runtime_throw("runtime_pollUnblock: already closing");
244 runtime_atomicstorep(&rg, nil); // full memory barrier between store to closing and read of rg/wg in netpollunblock
245 rg = netpollunblock(pd, 'r', false);
246 wg = netpollunblock(pd, 'w', false);
248 runtime_deltimer(&pd->rt);
252 runtime_deltimer(&pd->wt);
263 runtime_netpollfd(PollDesc *pd)
269 runtime_netpolluser(PollDesc *pd)
275 runtime_netpollclosing(PollDesc *pd)
281 runtime_netpolllock(PollDesc *pd)
287 runtime_netpollunlock(PollDesc *pd)
292 // make pd ready, newly runnable goroutines (if any) are enqueued info gpp list
294 runtime_netpollready(G **gpp, PollDesc *pd, int32 mode)
299 if(mode == 'r' || mode == 'r'+'w')
300 rg = netpollunblock(pd, 'r', true);
301 if(mode == 'w' || mode == 'r'+'w')
302 wg = netpollunblock(pd, 'w', true);
304 rg->schedlink = *gpp;
308 wg->schedlink = *gpp;
314 checkerr(PollDesc *pd, int32 mode)
317 return 1; // errClosing
318 if((mode == 'r' && pd->rd < 0) || (mode == 'w' && pd->wd < 0))
319 return 2; // errTimeout
324 blockcommit(G *gp, G **gpp)
326 return runtime_casp(gpp, WAIT, gp);
329 // returns true if IO is ready, or false if timedout or closed
330 // waitio - wait only for completed IO, ignore errors
332 netpollblock(PollDesc *pd, int32 mode, bool waitio)
340 // set the gpp semaphore to WAIT
348 runtime_throw("netpollblock: double wait");
349 if(runtime_casp(gpp, nil, WAIT))
353 // need to recheck error states after setting gpp to WAIT
354 // this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
355 // do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
356 if(waitio || checkerr(pd, mode) == 0)
357 runtime_park((bool(*)(G*, void*))blockcommit, gpp, "IO wait");
358 // be careful to not lose concurrent READY notification
359 old = runtime_xchgp(gpp, nil);
361 runtime_throw("netpollblock: corrupted state");
366 netpollunblock(PollDesc *pd, int32 mode, bool ioready)
378 if(old == nil && !ioready) {
379 // Only set READY for ioready. runtime_pollWait
380 // will check for timeout/cancel before waiting.
386 if(runtime_casp(gpp, old, new))
390 return old; // must be G*
395 deadlineimpl(Eface arg, uintptr seq, bool read, bool write)
400 pd = (PollDesc*)arg.data;
403 // Seq arg is seq when the timer was set.
404 // If it's stale, ignore the timer event.
406 // The descriptor was reused or timers were reset.
411 if(pd->rd <= 0 || pd->rt.fv == nil)
412 runtime_throw("deadlineimpl: inconsistent read deadline");
414 runtime_atomicstorep(&pd->rt.fv, nil); // full memory barrier between store to rd and load of rg in netpollunblock
415 rg = netpollunblock(pd, 'r', false);
418 if(pd->wd <= 0 || (pd->wt.fv == nil && !read))
419 runtime_throw("deadlineimpl: inconsistent write deadline");
421 runtime_atomicstorep(&pd->wt.fv, nil); // full memory barrier between store to wd and load of wg in netpollunblock
422 wg = netpollunblock(pd, 'w', false);
432 deadline(Eface arg, uintptr seq)
434 deadlineimpl(arg, seq, true, true);
438 readDeadline(Eface arg, uintptr seq)
440 deadlineimpl(arg, seq, true, false);
444 writeDeadline(Eface arg, uintptr seq)
446 deadlineimpl(arg, seq, false, true);
455 runtime_lock(&pollcache);
456 if(pollcache.first == nil) {
457 n = PollBlockSize/sizeof(*pd);
460 // Must be in non-GC memory because can be referenced
461 // only from epoll/kqueue internals.
462 pd = runtime_persistentalloc(n*sizeof(*pd), 0, &mstats.other_sys);
463 for(i = 0; i < n; i++) {
464 pd[i].link = pollcache.first;
465 pollcache.first = &pd[i];
468 pd = pollcache.first;
469 pollcache.first = pd->link;
470 runtime_unlock(&pollcache);