github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/netpoll_select.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 solaris 6 7 #include "config.h" 8 9 #include <errno.h> 10 #include <sys/times.h> 11 #include <sys/types.h> 12 #include <unistd.h> 13 #include <fcntl.h> 14 15 #ifdef HAVE_SYS_SELECT_H 16 #include <sys/select.h> 17 #endif 18 19 #include "runtime.h" 20 #include "malloc.h" 21 22 static Lock selectlock; 23 static int rdwake; 24 static int wrwake; 25 static fd_set fds; 26 static PollDesc **data; 27 static int allocated; 28 29 void 30 runtime_netpollinit(void) 31 { 32 int p[2]; 33 int fl; 34 35 FD_ZERO(&fds); 36 allocated = 128; 37 data = runtime_mallocgc(allocated * sizeof(PollDesc *), 0, 38 FlagNoScan|FlagNoProfiling|FlagNoInvokeGC); 39 40 if(pipe(p) < 0) 41 runtime_throw("netpollinit: failed to create pipe"); 42 rdwake = p[0]; 43 wrwake = p[1]; 44 45 fl = fcntl(rdwake, F_GETFL); 46 if(fl < 0) 47 runtime_throw("netpollinit: fcntl failed"); 48 fl |= O_NONBLOCK; 49 if(fcntl(rdwake, F_SETFL, fl)) 50 runtime_throw("netpollinit: fcntl failed"); 51 fcntl(rdwake, F_SETFD, FD_CLOEXEC); 52 53 fl = fcntl(wrwake, F_GETFL); 54 if(fl < 0) 55 runtime_throw("netpollinit: fcntl failed"); 56 fl |= O_NONBLOCK; 57 if(fcntl(wrwake, F_SETFL, fl)) 58 runtime_throw("netpollinit: fcntl failed"); 59 fcntl(wrwake, F_SETFD, FD_CLOEXEC); 60 61 FD_SET(rdwake, &fds); 62 } 63 64 int32 65 runtime_netpollopen(uintptr fd, PollDesc *pd) 66 { 67 byte b; 68 69 runtime_lock(&selectlock); 70 71 if((int)fd >= allocated) { 72 int c; 73 PollDesc **n; 74 75 c = allocated; 76 77 runtime_unlock(&selectlock); 78 79 while((int)fd >= c) 80 c *= 2; 81 n = runtime_mallocgc(c * sizeof(PollDesc *), 0, 82 FlagNoScan|FlagNoProfiling|FlagNoInvokeGC); 83 84 runtime_lock(&selectlock); 85 86 if(c > allocated) { 87 __builtin_memcpy(n, data, allocated * sizeof(PollDesc *)); 88 allocated = c; 89 data = n; 90 } 91 } 92 FD_SET(fd, &fds); 93 data[fd] = pd; 94 95 runtime_unlock(&selectlock); 96 97 b = 0; 98 write(wrwake, &b, sizeof b); 99 100 return 0; 101 } 102 103 int32 104 runtime_netpollclose(uintptr fd) 105 { 106 byte b; 107 108 runtime_lock(&selectlock); 109 110 FD_CLR(fd, &fds); 111 data[fd] = nil; 112 113 runtime_unlock(&selectlock); 114 115 b = 0; 116 write(wrwake, &b, sizeof b); 117 118 return 0; 119 } 120 121 /* Used to avoid using too much stack memory. */ 122 static bool inuse; 123 static fd_set grfds, gwfds, gefds, gtfds; 124 125 G* 126 runtime_netpoll(bool block) 127 { 128 fd_set *prfds, *pwfds, *pefds, *ptfds; 129 bool allocatedfds; 130 struct timeval timeout; 131 struct timeval *pt; 132 int max, c, i; 133 G *gp; 134 int32 mode; 135 byte b; 136 struct stat st; 137 138 allocatedfds = false; 139 140 retry: 141 runtime_lock(&selectlock); 142 143 max = allocated; 144 145 if(max == 0) { 146 runtime_unlock(&selectlock); 147 return nil; 148 } 149 150 if(inuse) { 151 if(!allocatedfds) { 152 prfds = runtime_SysAlloc(4 * sizeof fds, &mstats.other_sys); 153 pwfds = prfds + 1; 154 pefds = pwfds + 1; 155 ptfds = pefds + 1; 156 allocatedfds = true; 157 } 158 } else { 159 prfds = &grfds; 160 pwfds = &gwfds; 161 pefds = &gefds; 162 ptfds = >fds; 163 inuse = true; 164 allocatedfds = false; 165 } 166 167 __builtin_memcpy(prfds, &fds, sizeof fds); 168 169 runtime_unlock(&selectlock); 170 171 __builtin_memcpy(pwfds, prfds, sizeof fds); 172 FD_CLR(rdwake, pwfds); 173 __builtin_memcpy(pefds, pwfds, sizeof fds); 174 175 __builtin_memcpy(ptfds, pwfds, sizeof fds); 176 177 __builtin_memset(&timeout, 0, sizeof timeout); 178 pt = &timeout; 179 if(block) 180 pt = nil; 181 182 c = select(max, prfds, pwfds, pefds, pt); 183 if(c < 0) { 184 if(errno == EBADF) { 185 // Some file descriptor has been closed. 186 // Check each one, and treat each closed 187 // descriptor as ready for read/write. 188 c = 0; 189 FD_ZERO(prfds); 190 FD_ZERO(pwfds); 191 FD_ZERO(pefds); 192 for(i = 0; i < max; i++) { 193 if(FD_ISSET(i, ptfds) 194 && fstat(i, &st) < 0 195 && errno == EBADF) { 196 FD_SET(i, prfds); 197 FD_SET(i, pwfds); 198 c += 2; 199 } 200 } 201 } 202 else { 203 if(errno != EINTR) 204 runtime_printf("runtime: select failed with %d\n", errno); 205 goto retry; 206 } 207 } 208 gp = nil; 209 for(i = 0; i < max && c > 0; i++) { 210 mode = 0; 211 if(FD_ISSET(i, prfds)) { 212 mode += 'r'; 213 --c; 214 } 215 if(FD_ISSET(i, pwfds)) { 216 mode += 'w'; 217 --c; 218 } 219 if(FD_ISSET(i, pefds)) { 220 mode = 'r' + 'w'; 221 --c; 222 } 223 if(i == rdwake && mode != 0) { 224 while(read(rdwake, &b, sizeof b) > 0) 225 ; 226 continue; 227 } 228 if(mode) { 229 PollDesc *pd; 230 231 runtime_lock(&selectlock); 232 pd = data[i]; 233 runtime_unlock(&selectlock); 234 if(pd != nil) 235 runtime_netpollready(&gp, pd, mode); 236 } 237 } 238 if(block && gp == nil) 239 goto retry; 240 241 if(allocatedfds) { 242 runtime_SysFree(prfds, 4 * sizeof fds, &mstats.other_sys); 243 } else { 244 runtime_lock(&selectlock); 245 inuse = false; 246 runtime_unlock(&selectlock); 247 } 248 249 return gp; 250 } 251 252 void 253 runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj)) 254 { 255 enqueue1(wbufp, (Obj){(byte*)&data, sizeof data, 0}); 256 }