github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/netpoll_epoll.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 linux 6 7 #include <errno.h> 8 #include <unistd.h> 9 #include <fcntl.h> 10 #include <sys/epoll.h> 11 12 #include "runtime.h" 13 #include "defs.h" 14 #include "malloc.h" 15 16 #ifndef EPOLLRDHUP 17 #define EPOLLRDHUP 0x2000 18 #endif 19 20 #ifndef EPOLL_CLOEXEC 21 #define EPOLL_CLOEXEC 02000000 22 #endif 23 24 #ifndef HAVE_EPOLL_CREATE1 25 extern int epoll_create1(int __flags); 26 #endif 27 28 typedef struct epoll_event EpollEvent; 29 30 static int32 31 runtime_epollcreate(int32 size) 32 { 33 int r; 34 35 r = epoll_create(size); 36 if(r >= 0) 37 return r; 38 return - errno; 39 } 40 41 static int32 42 runtime_epollcreate1(int32 flags) 43 { 44 int r; 45 46 r = epoll_create1(flags); 47 if(r >= 0) 48 return r; 49 return - errno; 50 } 51 52 static int32 53 runtime_epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev) 54 { 55 int r; 56 57 r = epoll_ctl(epfd, op, fd, ev); 58 if(r >= 0) 59 return r; 60 return - errno; 61 } 62 63 static int32 64 runtime_epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout) 65 { 66 int r; 67 68 r = epoll_wait(epfd, ev, nev, timeout); 69 if(r >= 0) 70 return r; 71 return - errno; 72 } 73 74 static void 75 runtime_closeonexec(int32 fd) 76 { 77 fcntl(fd, F_SETFD, FD_CLOEXEC); 78 } 79 80 static int32 epfd = -1; // epoll descriptor 81 82 void 83 runtime_netpollinit(void) 84 { 85 epfd = runtime_epollcreate1(EPOLL_CLOEXEC); 86 if(epfd >= 0) 87 return; 88 epfd = runtime_epollcreate(1024); 89 if(epfd >= 0) { 90 runtime_closeonexec(epfd); 91 return; 92 } 93 runtime_printf("netpollinit: failed to create descriptor (%d)\n", -epfd); 94 runtime_throw("netpollinit: failed to create descriptor"); 95 } 96 97 int32 98 runtime_netpollopen(uintptr fd, PollDesc *pd) 99 { 100 EpollEvent ev; 101 int32 res; 102 103 ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET; 104 ev.data.ptr = (void*)pd; 105 res = runtime_epollctl(epfd, EPOLL_CTL_ADD, (int32)fd, &ev); 106 return -res; 107 } 108 109 int32 110 runtime_netpollclose(uintptr fd) 111 { 112 EpollEvent ev; 113 int32 res; 114 115 res = runtime_epollctl(epfd, EPOLL_CTL_DEL, (int32)fd, &ev); 116 return -res; 117 } 118 119 void 120 runtime_netpollarm(PollDesc* pd, int32 mode) 121 { 122 USED(pd); 123 USED(mode); 124 runtime_throw("unused"); 125 } 126 127 // polls for ready network connections 128 // returns list of goroutines that become runnable 129 G* 130 runtime_netpoll(bool block) 131 { 132 static int32 lasterr; 133 EpollEvent events[128], *ev; 134 int32 n, i, waitms, mode; 135 G *gp; 136 137 if(epfd == -1) 138 return nil; 139 waitms = -1; 140 if(!block) 141 waitms = 0; 142 retry: 143 n = runtime_epollwait(epfd, events, nelem(events), waitms); 144 if(n < 0) { 145 if(n != -EINTR && n != lasterr) { 146 lasterr = n; 147 runtime_printf("runtime: epollwait on fd %d failed with %d\n", epfd, -n); 148 } 149 goto retry; 150 } 151 gp = nil; 152 for(i = 0; i < n; i++) { 153 ev = &events[i]; 154 if(ev->events == 0) 155 continue; 156 mode = 0; 157 if(ev->events & (EPOLLIN|EPOLLRDHUP|EPOLLHUP|EPOLLERR)) 158 mode += 'r'; 159 if(ev->events & (EPOLLOUT|EPOLLHUP|EPOLLERR)) 160 mode += 'w'; 161 if(mode) 162 runtime_netpollready(&gp, (void*)ev->data.ptr, mode); 163 } 164 if(block && gp == nil) 165 goto retry; 166 return gp; 167 } 168 169 void 170 runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj)) 171 { 172 USED(wbufp); 173 USED(enqueue1); 174 }