github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/netpoll_kqueue.c (about) 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 6 7 #include "runtime.h" 8 #include "defs_GOOS_GOARCH.h" 9 10 // Integrated network poller (kqueue-based implementation). 11 12 int32 runtime·kqueue(void); 13 int32 runtime·kevent(int32, Kevent*, int32, Kevent*, int32, Timespec*); 14 void runtime·closeonexec(int32); 15 16 static int32 kq = -1; 17 18 void 19 runtime·netpollinit(void) 20 { 21 kq = runtime·kqueue(); 22 if(kq < 0) { 23 runtime·printf("netpollinit: kqueue failed with %d\n", -kq); 24 runtime·throw("netpollinit: kqueue failed"); 25 } 26 runtime·closeonexec(kq); 27 } 28 29 int32 30 runtime·netpollopen(int32 fd, PollDesc *pd) 31 { 32 Kevent ev[2]; 33 int32 n; 34 35 // Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR) 36 // for the whole fd lifetime. The notifications are automatically unregistered 37 // when fd is closed. 38 ev[0].ident = fd; 39 ev[0].filter = EVFILT_READ; 40 ev[0].flags = EV_ADD|EV_RECEIPT|EV_CLEAR; 41 ev[0].fflags = 0; 42 ev[0].data = 0; 43 ev[0].udata = (byte*)pd; 44 ev[1] = ev[0]; 45 ev[1].filter = EVFILT_WRITE; 46 n = runtime·kevent(kq, ev, 2, ev, 2, nil); 47 if(n < 0) 48 return -n; 49 if(n != 2 || 50 (ev[0].flags&EV_ERROR) == 0 || ev[0].ident != fd || ev[0].filter != EVFILT_READ || 51 (ev[1].flags&EV_ERROR) == 0 || ev[1].ident != fd || ev[1].filter != EVFILT_WRITE) 52 return EFAULT; // just to mark out from other errors 53 if(ev[0].data != 0) 54 return ev[0].data; 55 if(ev[1].data != 0) 56 return ev[1].data; 57 return 0; 58 } 59 60 int32 61 runtime·netpollclose(int32 fd) 62 { 63 // Don't need to unregister because calling close() 64 // on fd will remove any kevents that reference the descriptor. 65 USED(fd); 66 return 0; 67 } 68 69 // Polls for ready network connections. 70 // Returns list of goroutines that become runnable. 71 G* 72 runtime·netpoll(bool block) 73 { 74 static int32 lasterr; 75 Kevent events[64], *ev; 76 Timespec ts, *tp; 77 int32 n, i; 78 G *gp; 79 80 if(kq == -1) 81 return nil; 82 tp = nil; 83 if(!block) { 84 ts.tv_sec = 0; 85 ts.tv_nsec = 0; 86 tp = &ts; 87 } 88 gp = nil; 89 retry: 90 n = runtime·kevent(kq, nil, 0, events, nelem(events), tp); 91 if(n < 0) { 92 if(n != -EINTR && n != lasterr) { 93 lasterr = n; 94 runtime·printf("runtime: kevent on fd %d failed with %d\n", kq, -n); 95 } 96 goto retry; 97 } 98 for(i = 0; i < n; i++) { 99 ev = &events[i]; 100 if(ev->filter == EVFILT_READ) 101 runtime·netpollready(&gp, (PollDesc*)ev->udata, 'r'); 102 if(ev->filter == EVFILT_WRITE) 103 runtime·netpollready(&gp, (PollDesc*)ev->udata, 'w'); 104 } 105 if(block && gp == nil) 106 goto retry; 107 return gp; 108 }