// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build solaris #include "config.h" #include #include #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif #include "runtime.h" #include "malloc.h" static Lock selectlock; static int rdwake; static int wrwake; static fd_set fds; static PollDesc **data; static int allocated; void runtime_netpollinit(void) { int p[2]; int fl; FD_ZERO(&fds); allocated = 128; data = runtime_mallocgc(allocated * sizeof(PollDesc *), 0, FlagNoScan|FlagNoProfiling|FlagNoInvokeGC); if(pipe(p) < 0) runtime_throw("netpollinit: failed to create pipe"); rdwake = p[0]; wrwake = p[1]; fl = fcntl(rdwake, F_GETFL); if(fl < 0) runtime_throw("netpollinit: fcntl failed"); fl |= O_NONBLOCK; if(fcntl(rdwake, F_SETFL, fl)) runtime_throw("netpollinit: fcntl failed"); fcntl(rdwake, F_SETFD, FD_CLOEXEC); fl = fcntl(wrwake, F_GETFL); if(fl < 0) runtime_throw("netpollinit: fcntl failed"); fl |= O_NONBLOCK; if(fcntl(wrwake, F_SETFL, fl)) runtime_throw("netpollinit: fcntl failed"); fcntl(wrwake, F_SETFD, FD_CLOEXEC); FD_SET(rdwake, &fds); } int32 runtime_netpollopen(uintptr fd, PollDesc *pd) { byte b; runtime_lock(&selectlock); if((int)fd >= allocated) { int c; PollDesc **n; c = allocated; runtime_unlock(&selectlock); while((int)fd >= c) c *= 2; n = runtime_mallocgc(c * sizeof(PollDesc *), 0, FlagNoScan|FlagNoProfiling|FlagNoInvokeGC); runtime_lock(&selectlock); if(c > allocated) { __builtin_memcpy(n, data, allocated * sizeof(PollDesc *)); allocated = c; data = n; } } FD_SET(fd, &fds); data[fd] = pd; runtime_unlock(&selectlock); b = 0; write(wrwake, &b, sizeof b); return 0; } int32 runtime_netpollclose(uintptr fd) { byte b; runtime_lock(&selectlock); FD_CLR(fd, &fds); data[fd] = nil; runtime_unlock(&selectlock); b = 0; write(wrwake, &b, sizeof b); return 0; } /* Used to avoid using too much stack memory. */ static bool inuse; static fd_set grfds, gwfds, gefds, gtfds; G* runtime_netpoll(bool block) { fd_set *prfds, *pwfds, *pefds, *ptfds; bool allocatedfds; struct timeval timeout; struct timeval *pt; int max, c, i; G *gp; int32 mode; byte b; struct stat st; retry: runtime_lock(&selectlock); max = allocated; if(max == 0) { runtime_unlock(&selectlock); return nil; } if(inuse) { prfds = runtime_SysAlloc(4 * sizeof fds, &mstats.other_sys); pwfds = prfds + 1; pefds = pwfds + 1; ptfds = pefds + 1; allocatedfds = true; } else { prfds = &grfds; pwfds = &gwfds; pefds = &gefds; ptfds = >fds; inuse = true; allocatedfds = false; } __builtin_memcpy(prfds, &fds, sizeof fds); runtime_unlock(&selectlock); __builtin_memcpy(pwfds, prfds, sizeof fds); FD_CLR(rdwake, pwfds); __builtin_memcpy(pefds, pwfds, sizeof fds); __builtin_memcpy(ptfds, pwfds, sizeof fds); __builtin_memset(&timeout, 0, sizeof timeout); pt = &timeout; if(block) pt = nil; c = select(max, prfds, pwfds, pefds, pt); if(c < 0) { if(errno == EBADF) { // Some file descriptor has been closed. // Check each one, and treat each closed // descriptor as ready for read/write. c = 0; FD_ZERO(prfds); FD_ZERO(pwfds); FD_ZERO(pefds); for(i = 0; i < max; i++) { if(FD_ISSET(i, ptfds) && fstat(i, &st) < 0 && errno == EBADF) { FD_SET(i, prfds); FD_SET(i, pwfds); c += 2; } } } else { if(errno != EINTR) runtime_printf("runtime: select failed with %d\n", errno); goto retry; } } gp = nil; for(i = 0; i < max && c > 0; i++) { mode = 0; if(FD_ISSET(i, prfds)) { mode += 'r'; --c; } if(FD_ISSET(i, pwfds)) { mode += 'w'; --c; } if(FD_ISSET(i, pefds)) { mode = 'r' + 'w'; --c; } if(i == rdwake) { while(read(rdwake, &b, sizeof b) > 0) ; continue; } if(mode) { PollDesc *pd; runtime_lock(&selectlock); pd = data[i]; runtime_unlock(&selectlock); if(pd != nil) runtime_netpollready(&gp, pd, mode); } } if(block && gp == nil) goto retry; if(allocatedfds) { runtime_SysFree(prfds, 4 * sizeof fds, &mstats.other_sys); } else { runtime_lock(&selectlock); inuse = false; runtime_unlock(&selectlock); } return gp; } void runtime_netpoll_scan(void (*addroot)(Obj)) { addroot((Obj){(byte*)&data, sizeof data, 0}); }