From: Alex Brainman Date: Tue, 25 Jun 2013 02:29:00 +0000 (+1000) Subject: runtime: change netpoll in preparation for windows implementation X-Git-Tag: go1.2rc2~1182 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8486d96a2720d6ce36b8125f636306f9f224fcf3;p=gostls13.git runtime: change netpoll in preparation for windows implementation - change runtime_pollWait so it does not return closed or timeout if IO is ready - windows must know if IO has completed or not even after interruption; - add (*pollDesc).Prepare(mode int) that can be used for both read and write, same for Wait; - introduce runtime_pollWaitCanceled and expose it in net as (*pollDesc).WaitCanceled(mode int); Full windows netpoll changes are here https://golang.org/cl/8670044/. R=golang-dev, dvyukov CC=golang-dev https://golang.org/cl/10485043 --- diff --git a/src/pkg/net/fd_poll_runtime.go b/src/pkg/net/fd_poll_runtime.go index c76f1de7b7..03ab3e4292 100644 --- a/src/pkg/net/fd_poll_runtime.go +++ b/src/pkg/net/fd_poll_runtime.go @@ -16,6 +16,7 @@ func runtime_pollServerInit() func runtime_pollOpen(fd uintptr) (uintptr, int) func runtime_pollClose(ctx uintptr) func runtime_pollWait(ctx uintptr, mode int) int +func runtime_pollWaitCanceled(ctx uintptr, mode int) int func runtime_pollReset(ctx uintptr, mode int) int func runtime_pollSetDeadline(ctx uintptr, d int64, mode int) func runtime_pollUnblock(ctx uintptr) @@ -56,24 +57,42 @@ func (pd *pollDesc) Evict() bool { return false } -func (pd *pollDesc) PrepareRead() error { - res := runtime_pollReset(pd.runtimeCtx, 'r') +func (pd *pollDesc) Prepare(mode int) error { + res := runtime_pollReset(pd.runtimeCtx, mode) return convertErr(res) } +func (pd *pollDesc) PrepareRead() error { + return pd.Prepare('r') +} + func (pd *pollDesc) PrepareWrite() error { - res := runtime_pollReset(pd.runtimeCtx, 'w') + return pd.Prepare('w') +} + +func (pd *pollDesc) Wait(mode int) error { + res := runtime_pollWait(pd.runtimeCtx, mode) return convertErr(res) } func (pd *pollDesc) WaitRead() error { - res := runtime_pollWait(pd.runtimeCtx, 'r') - return convertErr(res) + return pd.Wait('r') } func (pd *pollDesc) WaitWrite() error { - res := runtime_pollWait(pd.runtimeCtx, 'w') - return convertErr(res) + return pd.Wait('w') +} + +func (pd *pollDesc) WaitCanceled(mode int) { + runtime_pollWaitCanceled(pd.runtimeCtx, mode) +} + +func (pd *pollDesc) WaitCanceledRead() { + pd.WaitCanceled('r') +} + +func (pd *pollDesc) WaitCanceledWrite() { + pd.WaitCanceled('w') } func convertErr(res int) error { @@ -85,6 +104,7 @@ func convertErr(res int) error { case 2: return errTimeout } + println("unreachable: ", res) panic("unreachable") } diff --git a/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc index 59420f781f..e9c0218393 100644 --- a/src/pkg/runtime/netpoll.goc +++ b/src/pkg/runtime/netpoll.goc @@ -47,8 +47,8 @@ static struct // seq is incremented when deadlines are changed or descriptor is reused. } pollcache; -static void netpollblock(PollDesc*, int32); -static G* netpollunblock(PollDesc*, int32); +static bool netpollblock(PollDesc*, int32); +static G* netpollunblock(PollDesc*, int32, bool); static void deadline(int64, Eface); static void readDeadline(int64, Eface); static void writeDeadline(int64, Eface); @@ -112,11 +112,21 @@ ret: func runtime_pollWait(pd *PollDesc, mode int) (err int) { runtime·lock(pd); err = checkerr(pd, mode); - if(err) - goto ret; - netpollblock(pd, mode); - err = checkerr(pd, mode); -ret: + if(err == 0) { + if(!netpollblock(pd, mode)) { + err = checkerr(pd, mode); + if(err == 0) + runtime·throw("runtime_pollWait: unblocked by ioready"); + } + } + runtime·unlock(pd); +} + +func runtime_pollWaitCanceled(pd *PollDesc, mode int) { + runtime·lock(pd); + // wait for ioready, ignore closing or timeouts. + while(!netpollblock(pd, mode)) + ; runtime·unlock(pd); } @@ -179,8 +189,8 @@ func runtime_pollUnblock(pd *PollDesc) { runtime·throw("runtime_pollUnblock: already closing"); pd->closing = true; pd->seq++; - rg = netpollunblock(pd, 'r'); - wg = netpollunblock(pd, 'w'); + rg = netpollunblock(pd, 'r', false); + wg = netpollunblock(pd, 'w', false); if(pd->rt.fv) { runtime·deltimer(&pd->rt); pd->rt.fv = nil; @@ -205,9 +215,9 @@ runtime·netpollready(G **gpp, PollDesc *pd, int32 mode) rg = wg = nil; runtime·lock(pd); if(mode == 'r' || mode == 'r'+'w') - rg = netpollunblock(pd, 'r'); + rg = netpollunblock(pd, 'r', true); if(mode == 'w' || mode == 'r'+'w') - wg = netpollunblock(pd, 'w'); + wg = netpollunblock(pd, 'w', true); runtime·unlock(pd); if(rg) { rg->schedlink = *gpp; @@ -229,7 +239,8 @@ checkerr(PollDesc *pd, int32 mode) return 0; } -static void +// returns true if IO is ready, or false if timedout or closed +static bool netpollblock(PollDesc *pd, int32 mode) { G **gpp; @@ -239,17 +250,20 @@ netpollblock(PollDesc *pd, int32 mode) gpp = &pd->wg; if(*gpp == READY) { *gpp = nil; - return; + return true; } if(*gpp != nil) runtime·throw("epoll: double wait"); *gpp = g; runtime·park(runtime·unlock, &pd->Lock, "IO wait"); runtime·lock(pd); + if(g->param) + return true; + return false; } static G* -netpollunblock(PollDesc *pd, int32 mode) +netpollunblock(PollDesc *pd, int32 mode, bool ioready) { G **gpp, *old; @@ -259,10 +273,15 @@ netpollunblock(PollDesc *pd, int32 mode) if(*gpp == READY) return nil; if(*gpp == nil) { - *gpp = READY; + // Only set READY for ioready. runtime_pollWait + // will check for timeout/cancel before waiting. + if(ioready) + *gpp = READY; return nil; } old = *gpp; + // pass unblock reason onto blocked g + old->param = (void*)ioready; *gpp = nil; return old; } @@ -291,14 +310,14 @@ deadlineimpl(int64 now, Eface arg, bool read, bool write) runtime·throw("deadlineimpl: inconsistent read deadline"); pd->rd = -1; pd->rt.fv = nil; - rg = netpollunblock(pd, 'r'); + rg = netpollunblock(pd, 'r', false); } if(write) { if(pd->wd <= 0 || (pd->wt.fv == nil && !read)) runtime·throw("deadlineimpl: inconsistent write deadline"); pd->wd = -1; pd->wt.fv = nil; - wg = netpollunblock(pd, 'w'); + wg = netpollunblock(pd, 'w', false); } runtime·unlock(pd); if(rg)