2014-07-29 Ed Smith-Rowland <3dw4rd@verizon.net>
[official-gcc.git] / libgo / runtime / netpoll_select.c
blobb46133591184c7cdc7ef1e78676b0515dc7243c4
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.
5 // +build solaris
7 #include "config.h"
9 #include <errno.h>
10 #include <sys/times.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 #include <fcntl.h>
15 #ifdef HAVE_SYS_SELECT_H
16 #include <sys/select.h>
17 #endif
19 #include "runtime.h"
20 #include "malloc.h"
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;
29 void
30 runtime_netpollinit(void)
32 int p[2];
33 int fl;
35 FD_ZERO(&fds);
36 allocated = 128;
37 data = runtime_mallocgc(allocated * sizeof(PollDesc *), 0,
38 FlagNoScan|FlagNoProfiling|FlagNoInvokeGC);
40 if(pipe(p) < 0)
41 runtime_throw("netpollinit: failed to create pipe");
42 rdwake = p[0];
43 wrwake = p[1];
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);
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);
61 FD_SET(rdwake, &fds);
64 int32
65 runtime_netpollopen(uintptr fd, PollDesc *pd)
67 byte b;
69 runtime_lock(&selectlock);
71 if((int)fd >= allocated) {
72 int c;
73 PollDesc **n;
75 c = allocated;
77 runtime_unlock(&selectlock);
79 while((int)fd >= c)
80 c *= 2;
81 n = runtime_mallocgc(c * sizeof(PollDesc *), 0,
82 FlagNoScan|FlagNoProfiling|FlagNoInvokeGC);
84 runtime_lock(&selectlock);
86 if(c > allocated) {
87 __builtin_memcpy(n, data, allocated * sizeof(PollDesc *));
88 allocated = c;
89 data = n;
92 FD_SET(fd, &fds);
93 data[fd] = pd;
95 runtime_unlock(&selectlock);
97 b = 0;
98 write(wrwake, &b, sizeof b);
100 return 0;
103 int32
104 runtime_netpollclose(uintptr fd)
106 byte b;
108 runtime_lock(&selectlock);
110 FD_CLR(fd, &fds);
111 data[fd] = nil;
113 runtime_unlock(&selectlock);
115 b = 0;
116 write(wrwake, &b, sizeof b);
118 return 0;
121 /* Used to avoid using too much stack memory. */
122 static bool inuse;
123 static fd_set grfds, gwfds, gefds, gtfds;
126 runtime_netpoll(bool block)
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;
138 retry:
139 runtime_lock(&selectlock);
141 max = allocated;
143 if(max == 0) {
144 runtime_unlock(&selectlock);
145 return nil;
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 = &gtfds;
159 inuse = true;
160 allocatedfds = false;
163 __builtin_memcpy(prfds, &fds, sizeof fds);
165 runtime_unlock(&selectlock);
167 __builtin_memcpy(pwfds, prfds, sizeof fds);
168 FD_CLR(rdwake, pwfds);
169 __builtin_memcpy(pefds, pwfds, sizeof fds);
171 __builtin_memcpy(ptfds, pwfds, sizeof fds);
173 __builtin_memset(&timeout, 0, sizeof timeout);
174 pt = &timeout;
175 if(block)
176 pt = nil;
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;
198 else {
199 if(errno != EINTR)
200 runtime_printf("runtime: select failed with %d\n", errno);
201 goto retry;
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;
211 if(FD_ISSET(i, pwfds)) {
212 mode += 'w';
213 --c;
215 if(FD_ISSET(i, pefds)) {
216 mode = 'r' + 'w';
217 --c;
219 if(i == rdwake) {
220 while(read(rdwake, &b, sizeof b) > 0)
222 continue;
224 if(mode) {
225 PollDesc *pd;
227 runtime_lock(&selectlock);
228 pd = data[i];
229 runtime_unlock(&selectlock);
230 if(pd != nil)
231 runtime_netpollready(&gp, pd, mode);
234 if(block && gp == nil)
235 goto retry;
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);
245 return gp;
248 void
249 runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
251 enqueue1(wbufp, (Obj){(byte*)&data, sizeof data, 0});