2013-10-24 Jan-Benedict Glaw <jbglaw@lug-owl.de>
[official-gcc.git] / libgo / runtime / netpoll_epoll.c
blob98c5cbeb58715ce3fdfd2227e33821d86e1e3d1f
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 linux
7 #include <errno.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/epoll.h>
12 #include "runtime.h"
13 #include "defs.h"
15 #ifndef EPOLLRDHUP
16 #define EPOLLRDHUP 0x2000
17 #endif
19 #ifndef EPOLL_CLOEXEC
20 #define EPOLL_CLOEXEC 02000000
21 #endif
23 #ifndef HAVE_EPOLL_CREATE1
24 extern int epoll_create1(int __flags);
25 #endif
27 typedef struct epoll_event EpollEvent;
29 static int32
30 runtime_epollcreate(int32 size)
32 int r;
34 r = epoll_create(size);
35 if(r >= 0)
36 return r;
37 return - errno;
40 static int32
41 runtime_epollcreate1(int32 flags)
43 int r;
45 r = epoll_create1(flags);
46 if(r >= 0)
47 return r;
48 return - errno;
51 static int32
52 runtime_epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev)
54 int r;
56 r = epoll_ctl(epfd, op, fd, ev);
57 if(r >= 0)
58 return r;
59 return - errno;
62 static int32
63 runtime_epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
65 int r;
67 r = epoll_wait(epfd, ev, nev, timeout);
68 if(r >= 0)
69 return r;
70 return - errno;
73 static void
74 runtime_closeonexec(int32 fd)
76 fcntl(fd, F_SETFD, FD_CLOEXEC);
79 static int32 epfd = -1; // epoll descriptor
81 void
82 runtime_netpollinit(void)
84 epfd = runtime_epollcreate1(EPOLL_CLOEXEC);
85 if(epfd >= 0)
86 return;
87 epfd = runtime_epollcreate(1024);
88 if(epfd >= 0) {
89 runtime_closeonexec(epfd);
90 return;
92 runtime_printf("netpollinit: failed to create descriptor (%d)\n", -epfd);
93 runtime_throw("netpollinit: failed to create descriptor");
96 int32
97 runtime_netpollopen(int32 fd, PollDesc *pd)
99 EpollEvent ev;
100 int32 res;
102 ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET;
103 ev.data.ptr = (void*)pd;
104 res = runtime_epollctl(epfd, EPOLL_CTL_ADD, fd, &ev);
105 return -res;
108 int32
109 runtime_netpollclose(int32 fd)
111 EpollEvent ev;
112 int32 res;
114 res = runtime_epollctl(epfd, EPOLL_CTL_DEL, fd, &ev);
115 return -res;
118 // polls for ready network connections
119 // returns list of goroutines that become runnable
121 runtime_netpoll(bool block)
123 static int32 lasterr;
124 EpollEvent events[128], *ev;
125 int32 n, i, waitms, mode;
126 G *gp;
128 if(epfd == -1)
129 return nil;
130 waitms = -1;
131 if(!block)
132 waitms = 0;
133 retry:
134 n = runtime_epollwait(epfd, events, nelem(events), waitms);
135 if(n < 0) {
136 if(n != -EINTR && n != lasterr) {
137 lasterr = n;
138 runtime_printf("runtime: epollwait on fd %d failed with %d\n", epfd, -n);
140 goto retry;
142 gp = nil;
143 for(i = 0; i < n; i++) {
144 ev = &events[i];
145 if(ev->events == 0)
146 continue;
147 mode = 0;
148 if(ev->events & (EPOLLIN|EPOLLRDHUP|EPOLLHUP|EPOLLERR))
149 mode += 'r';
150 if(ev->events & (EPOLLOUT|EPOLLHUP|EPOLLERR))
151 mode += 'w';
152 if(mode)
153 runtime_netpollready(&gp, (void*)ev->data.ptr, mode);
155 if(block && gp == nil)
156 goto retry;
157 return gp;