Home | History | Annotate | Download | only in runtime
      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.
      4 
      5 // +build darwin dragonfly freebsd netbsd openbsd
      6 
      7 package runtime
      8 
      9 // Integrated network poller (kqueue-based implementation).
     10 
     11 import "unsafe"
     12 
     13 func kqueue() int32
     14 
     15 //go:noescape
     16 func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
     17 func closeonexec(fd int32)
     18 
     19 var (
     20 	kq int32 = -1
     21 )
     22 
     23 func netpollinit() {
     24 	kq = kqueue()
     25 	if kq < 0 {
     26 		println("runtime: kqueue failed with", -kq)
     27 		throw("runtime: netpollinit failed")
     28 	}
     29 	closeonexec(kq)
     30 }
     31 
     32 func netpolldescriptor() uintptr {
     33 	return uintptr(kq)
     34 }
     35 
     36 func netpollopen(fd uintptr, pd *pollDesc) int32 {
     37 	// Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR)
     38 	// for the whole fd lifetime. The notifications are automatically unregistered
     39 	// when fd is closed.
     40 	var ev [2]keventt
     41 	*(*uintptr)(unsafe.Pointer(&ev[0].ident)) = fd
     42 	ev[0].filter = _EVFILT_READ
     43 	ev[0].flags = _EV_ADD | _EV_CLEAR
     44 	ev[0].fflags = 0
     45 	ev[0].data = 0
     46 	ev[0].udata = (*byte)(unsafe.Pointer(pd))
     47 	ev[1] = ev[0]
     48 	ev[1].filter = _EVFILT_WRITE
     49 	n := kevent(kq, &ev[0], 2, nil, 0, nil)
     50 	if n < 0 {
     51 		return -n
     52 	}
     53 	return 0
     54 }
     55 
     56 func netpollclose(fd uintptr) int32 {
     57 	// Don't need to unregister because calling close()
     58 	// on fd will remove any kevents that reference the descriptor.
     59 	return 0
     60 }
     61 
     62 func netpollarm(pd *pollDesc, mode int) {
     63 	throw("runtime: unused")
     64 }
     65 
     66 // Polls for ready network connections.
     67 // Returns list of goroutines that become runnable.
     68 func netpoll(block bool) *g {
     69 	if kq == -1 {
     70 		return nil
     71 	}
     72 	var tp *timespec
     73 	var ts timespec
     74 	if !block {
     75 		tp = &ts
     76 	}
     77 	var events [64]keventt
     78 retry:
     79 	n := kevent(kq, nil, 0, &events[0], int32(len(events)), tp)
     80 	if n < 0 {
     81 		if n != -_EINTR {
     82 			println("runtime: kevent on fd", kq, "failed with", -n)
     83 			throw("runtime: netpoll failed")
     84 		}
     85 		goto retry
     86 	}
     87 	var gp guintptr
     88 	for i := 0; i < int(n); i++ {
     89 		ev := &events[i]
     90 		var mode int32
     91 		switch ev.filter {
     92 		case _EVFILT_READ:
     93 			mode += 'r'
     94 
     95 			// On some systems when the read end of a pipe
     96 			// is closed the write end will not get a
     97 			// _EVFILT_WRITE event, but will get a
     98 			// _EVFILT_READ event with EV_EOF set.
     99 			// Note that setting 'w' here just means that we
    100 			// will wake up a goroutine waiting to write;
    101 			// that goroutine will try the write again,
    102 			// and the appropriate thing will happen based
    103 			// on what that write returns (success, EPIPE, EAGAIN).
    104 			if ev.flags&_EV_EOF != 0 {
    105 				mode += 'w'
    106 			}
    107 		case _EVFILT_WRITE:
    108 			mode += 'w'
    109 		}
    110 		if mode != 0 {
    111 			netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
    112 		}
    113 	}
    114 	if block && gp == 0 {
    115 		goto retry
    116 	}
    117 	return gp.ptr()
    118 }
    119