diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go index cc5a030acbc24bf21fe1dbef850fd63a18e5b078..2b418a86812149cedcb90a247e3932c96fc129ce 100644 --- a/src/pkg/net/fd_unix.go +++ b/src/pkg/net/fd_unix.go @@ -124,8 +124,10 @@ func (fd *netFD) decref() { fd.sysmu.Lock() fd.sysref-- if fd.closing && fd.sysref == 0 && fd.sysfile != nil { - fd.sysfile.Close() + // Poller may want to unregister fd in readiness notification mechanism, + // so this must be executed before sysfile.Close(). fd.pd.Close() + fd.sysfile.Close() fd.sysfile = nil fd.sysfd = -1 } diff --git a/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc index b314c653385b70c210d18878c369ac89247d817b..06b6d61727fc481c4a0fc933e6043a76deb9d20b 100644 --- a/src/pkg/runtime/netpoll.goc +++ b/src/pkg/runtime/netpoll.goc @@ -25,6 +25,7 @@ struct PollDesc { PollDesc* link; // in pollcache, protected by pollcache.Lock Lock; // protectes the following fields + int32 fd; bool closing; uintptr seq; // protects from stale timers and ready notifications G* rg; // G waiting for read or READY (binary semaphore) @@ -69,6 +70,7 @@ func runtime_pollOpen(fd int) (pd *PollDesc, errno int) { runtime·throw("runtime_pollOpen: blocked write on free descriptor"); if(pd->rg != nil && pd->rg != READY) runtime·throw("runtime_pollOpen: blocked read on free descriptor"); + pd->fd = fd; pd->closing = false; pd->seq++; pd->rg = nil; @@ -87,6 +89,7 @@ func runtime_pollClose(pd *PollDesc) { runtime·throw("runtime_pollClose: blocked write on closing descriptor"); if(pd->rg != nil && pd->rg != READY) runtime·throw("runtime_pollClose: blocked read on closing descriptor"); + runtime·netpollclose(pd->fd); runtime·lock(&pollcache); pd->link = pollcache.first; pollcache.first = pd; diff --git a/src/pkg/runtime/netpoll_epoll.c b/src/pkg/runtime/netpoll_epoll.c index 34ed78addb1817f5404e2e0c98f201bcf52c2509..d6ef0d1446c78b090ccf02d6ff818eb7f20a7153 100644 --- a/src/pkg/runtime/netpoll_epoll.c +++ b/src/pkg/runtime/netpoll_epoll.c @@ -34,10 +34,22 @@ int32 runtime·netpollopen(int32 fd, PollDesc *pd) { EpollEvent ev; + int32 res; ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET; ev.data = (uint64)pd; - return runtime·epollctl(epfd, EPOLL_CTL_ADD, fd, &ev); + res = runtime·epollctl(epfd, EPOLL_CTL_ADD, fd, &ev); + return -res; +} + +int32 +runtime·netpollclose(int32 fd) +{ + EpollEvent ev; + int32 res; + + res = runtime·epollctl(epfd, EPOLL_CTL_DEL, fd, &ev); + return -res; } // polls for ready network connections diff --git a/src/pkg/runtime/netpoll_kqueue.c b/src/pkg/runtime/netpoll_kqueue.c index 7603260565044e718dfd3e5883205bbaffbe5b12..ad721e293eea42cf107aad937d0a4493e960bd52 100644 --- a/src/pkg/runtime/netpoll_kqueue.c +++ b/src/pkg/runtime/netpoll_kqueue.c @@ -57,6 +57,15 @@ runtime·netpollopen(int32 fd, PollDesc *pd) return 0; } +int32 +runtime·netpollclose(int32 fd) +{ + // Don't need to unregister because calling close() + // on fd will remove any kevents that reference the descriptor. + USED(fd); + return 0; +} + // Polls for ready network connections. // Returns list of goroutines that become runnable. G* diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index d209a4dfcaf5401915b373944ee1b0638f46cdd2..46c77e3fd5e221882e189be183fef91c4b07382c 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -792,6 +792,7 @@ bool runtime·deltimer(Timer*); G* runtime·netpoll(bool); void runtime·netpollinit(void); int32 runtime·netpollopen(int32, PollDesc*); +int32 runtime·netpollclose(int32); void runtime·netpollready(G**, PollDesc*, int32); void runtime·crash(void);