2016-07-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
[official-gcc.git] / libgo / runtime / netpoll_select.c
blob033661d17f243134f3656d3e1f8d02dd4946abf4
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 allocatedfds = false;
140 retry:
141 runtime_lock(&selectlock);
143 max = allocated;
145 if(max == 0) {
146 runtime_unlock(&selectlock);
147 return nil;
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;
158 } else {
159 prfds = &grfds;
160 pwfds = &gwfds;
161 pefds = &gefds;
162 ptfds = &gtfds;
163 inuse = true;
164 allocatedfds = false;
167 __builtin_memcpy(prfds, &fds, sizeof fds);
169 runtime_unlock(&selectlock);
171 __builtin_memcpy(pwfds, prfds, sizeof fds);
172 FD_CLR(rdwake, pwfds);
173 __builtin_memcpy(pefds, pwfds, sizeof fds);
175 __builtin_memcpy(ptfds, pwfds, sizeof fds);
177 __builtin_memset(&timeout, 0, sizeof timeout);
178 pt = &timeout;
179 if(block)
180 pt = nil;
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;
202 else {
203 if(errno != EINTR)
204 runtime_printf("runtime: select failed with %d\n", errno);
205 goto retry;
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;
215 if(FD_ISSET(i, pwfds)) {
216 mode += 'w';
217 --c;
219 if(FD_ISSET(i, pefds)) {
220 mode = 'r' + 'w';
221 --c;
223 if(i == rdwake && mode != 0) {
224 while(read(rdwake, &b, sizeof b) > 0)
226 continue;
228 if(mode) {
229 PollDesc *pd;
231 runtime_lock(&selectlock);
232 pd = data[i];
233 runtime_unlock(&selectlock);
234 if(pd != nil)
235 runtime_netpollready(&gp, pd, mode);
238 if(block && gp == nil)
239 goto retry;
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);
249 return gp;
252 void
253 runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
255 enqueue1(wbufp, (Obj){(byte*)&data, sizeof data, 0});