Importing Upstream version 4.8.2
[platform/upstream/gcc48.git] / libgo / runtime / netpoll_epoll.c
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 linux
6
7 #include <errno.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/epoll.h>
11
12 #include "runtime.h"
13 #include "defs.h"
14
15 #ifndef EPOLLRDHUP
16 #define EPOLLRDHUP 0x2000
17 #endif
18
19 #ifndef EPOLL_CLOEXEC
20 #define EPOLL_CLOEXEC 02000000
21 #endif
22
23 #ifndef HAVE_EPOLL_CREATE1
24 extern int epoll_create1(int __flags);
25 #endif
26
27 typedef struct epoll_event EpollEvent;
28
29 static int32
30 runtime_epollcreate(int32 size)
31 {
32         int r;
33
34         r = epoll_create(size);
35         if(r >= 0)
36                 return r;
37         return - errno;
38 }
39
40 static int32
41 runtime_epollcreate1(int32 flags)
42 {
43         int r;
44
45         r = epoll_create1(flags);
46         if(r >= 0)
47                 return r;
48         return - errno;
49 }
50
51 static int32
52 runtime_epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev)
53 {
54         int r;
55
56         r = epoll_ctl(epfd, op, fd, ev);
57         if(r >= 0)
58                 return r;
59         return - errno;
60 }
61
62 static int32
63 runtime_epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
64 {
65         int r;
66
67         r = epoll_wait(epfd, ev, nev, timeout);
68         if(r >= 0)
69                 return r;
70         return - errno;
71 }
72
73 static void
74 runtime_closeonexec(int32 fd)
75 {
76         fcntl(fd, F_SETFD, FD_CLOEXEC);
77 }
78
79 static int32 epfd = -1;  // epoll descriptor
80
81 void
82 runtime_netpollinit(void)
83 {
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;
91         }
92         runtime_printf("netpollinit: failed to create descriptor (%d)\n", -epfd);
93         runtime_throw("netpollinit: failed to create descriptor");
94 }
95
96 int32
97 runtime_netpollopen(int32 fd, PollDesc *pd)
98 {
99         EpollEvent ev;
100         int32 res;
101
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;
106 }
107
108 int32
109 runtime_netpollclose(int32 fd)
110 {
111         EpollEvent ev;
112         int32 res;
113
114         res = runtime_epollctl(epfd, EPOLL_CTL_DEL, fd, &ev);
115         return -res;
116 }
117
118 // polls for ready network connections
119 // returns list of goroutines that become runnable
120 G*
121 runtime_netpoll(bool block)
122 {
123         static int32 lasterr;
124         EpollEvent events[128], *ev;
125         int32 n, i, waitms, mode;
126         G *gp;
127
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);
139                 }
140                 goto retry;
141         }
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);
154         }
155         if(block && gp == nil)
156                 goto retry;
157         return gp;
158 }