github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/netpoll_epoll.c (about)

     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  #include "malloc.h"
    15  
    16  #ifndef EPOLLRDHUP
    17  #define EPOLLRDHUP 0x2000
    18  #endif
    19  
    20  #ifndef EPOLL_CLOEXEC
    21  #define EPOLL_CLOEXEC 02000000
    22  #endif
    23  
    24  #ifndef HAVE_EPOLL_CREATE1
    25  extern int epoll_create1(int __flags);
    26  #endif
    27  
    28  typedef struct epoll_event EpollEvent;
    29  
    30  static int32
    31  runtime_epollcreate(int32 size)
    32  {
    33  	int r;
    34  
    35  	r = epoll_create(size);
    36  	if(r >= 0)
    37  		return r;
    38  	return - errno;
    39  }
    40  
    41  static int32
    42  runtime_epollcreate1(int32 flags)
    43  {
    44  	int r;
    45  
    46  	r = epoll_create1(flags);
    47  	if(r >= 0)
    48  		return r;
    49  	return - errno;
    50  }
    51  
    52  static int32
    53  runtime_epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev)
    54  {
    55  	int r;
    56  
    57  	r = epoll_ctl(epfd, op, fd, ev);
    58  	if(r >= 0)
    59  		return r;
    60  	return - errno;
    61  }
    62  
    63  static int32
    64  runtime_epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
    65  {
    66  	int r;
    67  
    68  	r = epoll_wait(epfd, ev, nev, timeout);
    69  	if(r >= 0)
    70  		return r;
    71  	return - errno;
    72  }
    73  
    74  static void
    75  runtime_closeonexec(int32 fd)
    76  {
    77  	fcntl(fd, F_SETFD, FD_CLOEXEC);
    78  }
    79  
    80  static int32 epfd = -1;  // epoll descriptor
    81  
    82  void
    83  runtime_netpollinit(void)
    84  {
    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;
    92  	}
    93  	runtime_printf("netpollinit: failed to create descriptor (%d)\n", -epfd);
    94  	runtime_throw("netpollinit: failed to create descriptor");
    95  }
    96  
    97  int32
    98  runtime_netpollopen(uintptr fd, PollDesc *pd)
    99  {
   100  	EpollEvent ev;
   101  	int32 res;
   102  
   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;
   107  }
   108  
   109  int32
   110  runtime_netpollclose(uintptr fd)
   111  {
   112  	EpollEvent ev;
   113  	int32 res;
   114  
   115  	res = runtime_epollctl(epfd, EPOLL_CTL_DEL, (int32)fd, &ev);
   116  	return -res;
   117  }
   118  
   119  void
   120  runtime_netpollarm(PollDesc* pd, int32 mode)
   121  {
   122  	USED(pd);
   123  	USED(mode);
   124  	runtime_throw("unused");
   125  }
   126  
   127  // polls for ready network connections
   128  // returns list of goroutines that become runnable
   129  G*
   130  runtime_netpoll(bool block)
   131  {
   132  	static int32 lasterr;
   133  	EpollEvent events[128], *ev;
   134  	int32 n, i, waitms, mode;
   135  	G *gp;
   136  
   137  	if(epfd == -1)
   138  		return nil;
   139  	waitms = -1;
   140  	if(!block)
   141  		waitms = 0;
   142  retry:
   143  	n = runtime_epollwait(epfd, events, nelem(events), waitms);
   144  	if(n < 0) {
   145  		if(n != -EINTR && n != lasterr) {
   146  			lasterr = n;
   147  			runtime_printf("runtime: epollwait on fd %d failed with %d\n", epfd, -n);
   148  		}
   149  		goto retry;
   150  	}
   151  	gp = nil;
   152  	for(i = 0; i < n; i++) {
   153  		ev = &events[i];
   154  		if(ev->events == 0)
   155  			continue;
   156  		mode = 0;
   157  		if(ev->events & (EPOLLIN|EPOLLRDHUP|EPOLLHUP|EPOLLERR))
   158  			mode += 'r';
   159  		if(ev->events & (EPOLLOUT|EPOLLHUP|EPOLLERR))
   160  			mode += 'w';
   161  		if(mode)
   162  			runtime_netpollready(&gp, (void*)ev->data.ptr, mode);
   163  	}
   164  	if(block && gp == nil)
   165  		goto retry;
   166  	return gp;
   167  }
   168  
   169  void
   170  runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
   171  {
   172  	USED(wbufp);
   173  	USED(enqueue1);
   174  }