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 aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
10 "runtime/internal/atomic"
14 // Export temporarily for gccgo's C code to call:
15 //go:linkname netpoll runtime.netpoll
17 // Integrated network poller (platform-independent part).
18 // A particular implementation (epoll/kqueue) must define the following functions:
19 // func netpollinit() // to initialize the poller
20 // func netpollopen(fd uintptr, pd *pollDesc) int32 // to arm edge-triggered notifications
21 // and associate fd with pd.
22 // An implementation must call the following function to denote that the pd is ready.
23 // func netpollready(gpp **g, pd *pollDesc, mode int32)
25 // pollDesc contains 2 binary semaphores, rg and wg, to park reader and writer
26 // goroutines respectively. The semaphore can be in the following states:
27 // pdReady - io readiness notification is pending;
28 // a goroutine consumes the notification by changing the state to nil.
29 // pdWait - a goroutine prepares to park on the semaphore, but not yet parked;
30 // the goroutine commits to park by changing the state to G pointer,
31 // or, alternatively, concurrent io notification changes the state to READY,
32 // or, alternatively, concurrent timeout/close changes the state to nil.
33 // G pointer - the goroutine is blocked on the semaphore;
34 // io notification or timeout/close changes the state to READY or nil respectively
35 // and unparks the goroutine.
36 // nil - nothing of the above.
42 const pollBlockSize
= 4 * 1024
44 // Network poller descriptor.
49 type pollDesc
struct {
50 link
*pollDesc
// in pollcache, protected by pollcache.lock
52 // The lock protects pollOpen, pollSetDeadline, pollUnblock and deadlineimpl operations.
53 // This fully covers seq, rt and wt variables. fd is constant throughout the PollDesc lifetime.
54 // pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO readiness notification)
55 // proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
56 // in a lock-free way by all operations.
57 // NOTE(dvyukov): the following code uses uintptr to store *g (rg/wg),
58 // that will blow up when GC starts moving objects.
59 lock mutex
// protects the following fields
62 seq
uintptr // protects from stale timers and ready notifications
63 rg
uintptr // pdReady, pdWait, G waiting for read or nil
64 rt timer
// read deadline timer (set if rt.f != nil)
65 rd
int64 // read deadline
66 wg
uintptr // pdReady, pdWait, G waiting for write or nil
67 wt timer
// write deadline timer
68 wd
int64 // write deadline
69 user
uint32 // user settable cookie
72 type pollCache
struct {
75 // PollDesc objects must be type-stable,
76 // because we can get ready notification from epoll/kqueue
77 // after the descriptor is closed/reused.
78 // Stale notifications are detected using seq variable,
79 // seq is incremented when deadlines are changed or descriptor is reused.
88 //go:linkname poll_runtime_pollServerInit internal_poll.runtime_pollServerInit
89 func poll_runtime_pollServerInit() {
91 atomic
.Store(&netpollInited
, 1)
94 func netpollinited() bool {
95 return atomic
.Load(&netpollInited
) != 0
98 //go:linkname poll_runtime_pollServerDescriptor internal_poll.runtime_pollServerDescriptor
100 // poll_runtime_pollServerDescriptor returns the descriptor being used,
101 // or ^uintptr(0) if the system does not use a poll descriptor.
102 func poll_runtime_pollServerDescriptor() uintptr {
103 return netpolldescriptor()
106 //go:linkname poll_runtime_pollOpen internal_poll.runtime_pollOpen
107 func poll_runtime_pollOpen(fd
uintptr) (*pollDesc
, int) {
108 pd
:= pollcache
.alloc()
110 if pd
.wg
!= 0 && pd
.wg
!= pdReady
{
111 throw("runtime: blocked write on free polldesc")
113 if pd
.rg
!= 0 && pd
.rg
!= pdReady
{
114 throw("runtime: blocked read on free polldesc")
126 errno
= netpollopen(fd
, pd
)
127 return pd
, int(errno
)
130 //go:linkname poll_runtime_pollClose internal_poll.runtime_pollClose
131 func poll_runtime_pollClose(pd
*pollDesc
) {
133 throw("runtime: close polldesc w/o unblock")
135 if pd
.wg
!= 0 && pd
.wg
!= pdReady
{
136 throw("runtime: blocked write on closing polldesc")
138 if pd
.rg
!= 0 && pd
.rg
!= pdReady
{
139 throw("runtime: blocked read on closing polldesc")
145 func (c
*pollCache
) free(pd
*pollDesc
) {
152 //go:linkname poll_runtime_pollReset internal_poll.runtime_pollReset
153 func poll_runtime_pollReset(pd
*pollDesc
, mode
int) int {
154 err
:= netpollcheckerr(pd
, int32(mode
))
160 } else if mode
== 'w' {
166 //go:linkname poll_runtime_pollWait internal_poll.runtime_pollWait
167 func poll_runtime_pollWait(pd
*pollDesc
, mode
int) int {
168 err
:= netpollcheckerr(pd
, int32(mode
))
172 // As for now only Solaris uses level-triggered IO.
173 if GOOS
== "solaris" {
176 for !netpollblock(pd
, int32(mode
), false) {
177 err
= netpollcheckerr(pd
, int32(mode
))
181 // Can happen if timeout has fired and unblocked us,
182 // but before we had a chance to run, timeout has been reset.
183 // Pretend it has not happened and retry.
188 //go:linkname poll_runtime_pollWaitCanceled internal_poll.runtime_pollWaitCanceled
189 func poll_runtime_pollWaitCanceled(pd
*pollDesc
, mode
int) {
190 // This function is used only on windows after a failed attempt to cancel
191 // a pending async IO operation. Wait for ioready, ignore closing or timeouts.
192 for !netpollblock(pd
, int32(mode
), true) {
196 //go:linkname poll_runtime_pollSetDeadline internal_poll.runtime_pollSetDeadline
197 func poll_runtime_pollSetDeadline(pd
*pollDesc
, d
int64, mode
int) {
203 pd
.seq
++ // invalidate current timers
204 // Reset current timers.
214 if d
!= 0 && d
<= nanotime() {
217 if mode
== 'r' || mode
== 'r'+'w' {
220 if mode
== 'w' || mode
== 'r'+'w' {
223 if pd
.rd
> 0 && pd
.rd
== pd
.wd
{
224 pd
.rt
.f
= netpollDeadline
226 // Copy current seq into the timer arg.
227 // Timer func will check the seq against current descriptor seq,
228 // if they differ the descriptor was reused or timers were reset.
234 pd
.rt
.f
= netpollReadDeadline
241 pd
.wt
.f
= netpollWriteDeadline
248 // If we set the new deadline in the past, unblock currently pending IO if any.
250 atomicstorep(unsafe
.Pointer(&wg
), nil) // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
252 rg
= netpollunblock(pd
, 'r', false)
255 wg
= netpollunblock(pd
, 'w', false)
259 netpollgoready(rg
, 3)
262 netpollgoready(wg
, 3)
266 //go:linkname poll_runtime_pollUnblock internal_poll.runtime_pollUnblock
267 func poll_runtime_pollUnblock(pd
*pollDesc
) {
270 throw("runtime: unblock on closing polldesc")
275 atomicstorep(unsafe
.Pointer(&rg
), nil) // full memory barrier between store to closing and read of rg/wg in netpollunblock
276 rg
= netpollunblock(pd
, 'r', false)
277 wg
= netpollunblock(pd
, 'w', false)
288 netpollgoready(rg
, 3)
291 netpollgoready(wg
, 3)
295 // make pd ready, newly runnable goroutines (if any) are returned in rg/wg
296 // May run during STW, so write barriers are not allowed.
298 func netpollready(gpp
*guintptr
, pd
*pollDesc
, mode
int32) {
300 if mode
== 'r' || mode
== 'r'+'w' {
301 rg
.set(netpollunblock(pd
, 'r', true))
303 if mode
== 'w' || mode
== 'r'+'w' {
304 wg
.set(netpollunblock(pd
, 'w', true))
307 rg
.ptr().schedlink
= *gpp
311 wg
.ptr().schedlink
= *gpp
316 func netpollcheckerr(pd
*pollDesc
, mode
int32) int {
318 return 1 // errClosing
320 if (mode
== 'r' && pd
.rd
< 0) ||
(mode
== 'w' && pd
.wd
< 0) {
321 return 2 // errTimeout
326 func netpollblockcommit(gp
*g
, gpp unsafe
.Pointer
) bool {
327 r
:= atomic
.Casuintptr((*uintptr)(gpp
), pdWait
, uintptr(unsafe
.Pointer(gp
)))
329 // Bump the count of goroutines waiting for the poller.
330 // The scheduler uses this to decide whether to block
331 // waiting for the poller if there is nothing else to do.
332 atomic
.Xadd(&netpollWaiters
, 1)
337 func netpollgoready(gp
*g
, traceskip
int) {
338 atomic
.Xadd(&netpollWaiters
, -1)
339 goready(gp
, traceskip
+1)
342 // returns true if IO is ready, or false if timedout or closed
343 // waitio - wait only for completed IO, ignore errors
344 func netpollblock(pd
*pollDesc
, mode
int32, waitio
bool) bool {
350 // set the gpp semaphore to WAIT
358 throw("runtime: double wait")
360 if atomic
.Casuintptr(gpp
, 0, pdWait
) {
365 // need to recheck error states after setting gpp to WAIT
366 // this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
367 // do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
368 if waitio ||
netpollcheckerr(pd
, mode
) == 0 {
369 gopark(netpollblockcommit
, unsafe
.Pointer(gpp
), "IO wait", traceEvGoBlockNet
, 5)
371 // be careful to not lose concurrent READY notification
372 old
:= atomic
.Xchguintptr(gpp
, 0)
374 throw("runtime: corrupted polldesc")
376 return old
== pdReady
379 func netpollunblock(pd
*pollDesc
, mode
int32, ioready
bool) *g
{
390 if old
== 0 && !ioready
{
391 // Only set READY for ioready. runtime_pollWait
392 // will check for timeout/cancel before waiting.
399 if atomic
.Casuintptr(gpp
, old
, new) {
400 if old
== pdReady || old
== pdWait
{
403 return (*g
)(unsafe
.Pointer(old
))
408 func netpolldeadlineimpl(pd
*pollDesc
, seq
uintptr, read
, write
bool) {
410 // Seq arg is seq when the timer was set.
411 // If it's stale, ignore the timer event.
413 // The descriptor was reused or timers were reset.
419 if pd
.rd
<= 0 || pd
.rt
.f
== nil {
420 throw("runtime: inconsistent read deadline")
423 atomicstorep(unsafe
.Pointer(&pd
.rt
.f
), nil) // full memory barrier between store to rd and load of rg in netpollunblock
424 rg
= netpollunblock(pd
, 'r', false)
428 if pd
.wd
<= 0 || pd
.wt
.f
== nil && !read
{
429 throw("runtime: inconsistent write deadline")
432 atomicstorep(unsafe
.Pointer(&pd
.wt
.f
), nil) // full memory barrier between store to wd and load of wg in netpollunblock
433 wg
= netpollunblock(pd
, 'w', false)
437 netpollgoready(rg
, 0)
440 netpollgoready(wg
, 0)
444 func netpollDeadline(arg
interface{}, seq
uintptr) {
445 netpolldeadlineimpl(arg
.(*pollDesc
), seq
, true, true)
448 func netpollReadDeadline(arg
interface{}, seq
uintptr) {
449 netpolldeadlineimpl(arg
.(*pollDesc
), seq
, true, false)
452 func netpollWriteDeadline(arg
interface{}, seq
uintptr) {
453 netpolldeadlineimpl(arg
.(*pollDesc
), seq
, false, true)
456 func (c
*pollCache
) alloc() *pollDesc
{
459 const pdSize
= unsafe
.Sizeof(pollDesc
{})
460 n
:= pollBlockSize
/ pdSize
464 // Must be in non-GC memory because can be referenced
465 // only from epoll/kqueue internals.
466 mem
:= persistentalloc(n
*pdSize
, 0, &memstats
.other_sys
)
467 for i
:= uintptr(0); i
< n
; i
++ {
468 pd
:= (*pollDesc
)(add(mem
, i
*pdSize
))