github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/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 retry: 139 runtime_lock(&selectlock); 140 141 max = allocated; 142 143 if(max == 0) { 144 runtime_unlock(&selectlock); 145 return nil; 146 } 147 148 if(inuse) { 149 prfds = runtime_SysAlloc(4 * sizeof fds, &mstats.other_sys); 150 pwfds = prfds + 1; 151 pefds = pwfds + 1; 152 ptfds = pefds + 1; 153 allocatedfds = true; 154 } else { 155 prfds = &grfds; 156 pwfds = &gwfds; 157 pefds = &gefds; 158 ptfds = >fds; 159 inuse = true; 160 allocatedfds = false; 161 } 162 163 __builtin_memcpy(prfds, &fds, sizeof fds); 164 165 runtime_unlock(&selectlock); 166 167 __builtin_memcpy(pwfds, prfds, sizeof fds); 168 FD_CLR(rdwake, pwfds); 169 __builtin_memcpy(pefds, pwfds, sizeof fds); 170 171 __builtin_memcpy(ptfds, pwfds, sizeof fds); 172 173 __builtin_memset(&timeout, 0, sizeof timeout); 174 pt = &timeout; 175 if(block) 176 pt = nil; 177 178 c = select(max, prfds, pwfds, pefds, pt); 179 if(c < 0) { 180 if(errno == EBADF) { 181 // Some file descriptor has been closed. 182 // Check each one, and treat each closed 183 // descriptor as ready for read/write. 184 c = 0; 185 FD_ZERO(prfds); 186 FD_ZERO(pwfds); 187 FD_ZERO(pefds); 188 for(i = 0; i < max; i++) { 189 if(FD_ISSET(i, ptfds) 190 && fstat(i, &st) < 0 191 && errno == EBADF) { 192 FD_SET(i, prfds); 193 FD_SET(i, pwfds); 194 c += 2; 195 } 196 } 197 } 198 else { 199 if(errno != EINTR) 200 runtime_printf("runtime: select failed with %d\n", errno); 201 goto retry; 202 } 203 } 204 gp = nil; 205 for(i = 0; i < max && c > 0; i++) { 206 mode = 0; 207 if(FD_ISSET(i, prfds)) { 208 mode += 'r'; 209 --c; 210 } 211 if(FD_ISSET(i, pwfds)) { 212 mode += 'w'; 213 --c; 214 } 215 if(FD_ISSET(i, pefds)) { 216 mode = 'r' + 'w'; 217 --c; 218 } 219 if(i == rdwake) { 220 while(read(rdwake, &b, sizeof b) > 0) 221 ; 222 continue; 223 } 224 if(mode) { 225 PollDesc *pd; 226 227 runtime_lock(&selectlock); 228 pd = data[i]; 229 runtime_unlock(&selectlock); 230 if(pd != nil) 231 runtime_netpollready(&gp, pd, mode); 232 } 233 } 234 if(block && gp == nil) 235 goto retry; 236 237 if(allocatedfds) { 238 runtime_SysFree(prfds, 4 * sizeof fds, &mstats.other_sys); 239 } else { 240 runtime_lock(&selectlock); 241 inuse = false; 242 runtime_unlock(&selectlock); 243 } 244 245 return gp; 246 } 247 248 void 249 runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj)) 250 { 251 enqueue1(wbufp, (Obj){(byte*)&data, sizeof data, 0}); 252 }