2014-05-21 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / libgo / runtime / netpoll_epoll.c
blob2acbca32322151c38ae30106c22fecac2801d2fb
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"
14 #include "malloc.h"
16 #ifndef EPOLLRDHUP
17 #define EPOLLRDHUP 0x2000
18 #endif
20 #ifndef EPOLL_CLOEXEC
21 #define EPOLL_CLOEXEC 02000000
22 #endif
24 #ifndef HAVE_EPOLL_CREATE1
25 extern int epoll_create1(int __flags);
26 #endif
28 typedef struct epoll_event EpollEvent;
30 static int32
31 runtime_epollcreate(int32 size)
33 int r;
35 r = epoll_create(size);
36 if(r >= 0)
37 return r;
38 return - errno;
41 static int32
42 runtime_epollcreate1(int32 flags)
44 int r;
46 r = epoll_create1(flags);
47 if(r >= 0)
48 return r;
49 return - errno;
52 static int32
53 runtime_epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev)
55 int r;
57 r = epoll_ctl(epfd, op, fd, ev);
58 if(r >= 0)
59 return r;
60 return - errno;
63 static int32
64 runtime_epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
66 int r;
68 r = epoll_wait(epfd, ev, nev, timeout);
69 if(r >= 0)
70 return r;
71 return - errno;
74 static void
75 runtime_closeonexec(int32 fd)
77 fcntl(fd, F_SETFD, FD_CLOEXEC);
80 static int32 epfd = -1; // epoll descriptor
82 void
83 runtime_netpollinit(void)
85 epfd = runtime_epollcreate1(EPOLL_CLOEXEC);
86 if(epfd >= 0)
87 return;
88 epfd = runtime_epollcreate(1024);
89 if(epfd >= 0) {
90 runtime_closeonexec(epfd);
91 return;
93 runtime_printf("netpollinit: failed to create descriptor (%d)\n", -epfd);
94 runtime_throw("netpollinit: failed to create descriptor");
97 int32
98 runtime_netpollopen(uintptr fd, PollDesc *pd)
100 EpollEvent ev;
101 int32 res;
103 ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET;
104 ev.data.ptr = (void*)pd;
105 res = runtime_epollctl(epfd, EPOLL_CTL_ADD, (int32)fd, &ev);
106 return -res;
109 int32
110 runtime_netpollclose(uintptr fd)
112 EpollEvent ev;
113 int32 res;
115 res = runtime_epollctl(epfd, EPOLL_CTL_DEL, (int32)fd, &ev);
116 return -res;
119 // polls for ready network connections
120 // returns list of goroutines that become runnable
122 runtime_netpoll(bool block)
124 static int32 lasterr;
125 EpollEvent events[128], *ev;
126 int32 n, i, waitms, mode;
127 G *gp;
129 if(epfd == -1)
130 return nil;
131 waitms = -1;
132 if(!block)
133 waitms = 0;
134 retry:
135 n = runtime_epollwait(epfd, events, nelem(events), waitms);
136 if(n < 0) {
137 if(n != -EINTR && n != lasterr) {
138 lasterr = n;
139 runtime_printf("runtime: epollwait on fd %d failed with %d\n", epfd, -n);
141 goto retry;
143 gp = nil;
144 for(i = 0; i < n; i++) {
145 ev = &events[i];
146 if(ev->events == 0)
147 continue;
148 mode = 0;
149 if(ev->events & (EPOLLIN|EPOLLRDHUP|EPOLLHUP|EPOLLERR))
150 mode += 'r';
151 if(ev->events & (EPOLLOUT|EPOLLHUP|EPOLLERR))
152 mode += 'w';
153 if(mode)
154 runtime_netpollready(&gp, (void*)ev->data.ptr, mode);
156 if(block && gp == nil)
157 goto retry;
158 return gp;
161 void
162 runtime_netpoll_scan(void (*addroot)(Obj))
164 USED(addroot);