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);