Overview
Artifact ID: | 0c6a16db60e52858792ed35de9315af59c1e24a3 |
---|---|
Ticket: | 97069ea11aca3783949c0379725eed90f5573c23
close returns empty error message if failed non-blocking write flush pending |
User & Date: | oehhar 2014-03-25 09:55:25 |
Changes
- comment changed to:
<h1>Issue</h1> The trailing close in the following sequence throws an error but no error message: <verbatim> % set sock [socket -async localhost 30001] sock420 % fconfigure $sock -blocking 0 % puts $sock ok % flush $sock % fileevent $sock writable {set x 1} % vwait x % catch {close $sock} e d 1 % set e % set d -code 1 -level 0 -errorstack {INNER {invokeStk1 close sock420}} -errorcode NONE -errorinfo { while executing "close $sock"} -errorline 1 </verbatim> There are two conditions: * The socket connect must fail * flush $sock is executed before the socket connect internally failed. For machines where this is to quick, one must use another host instead localhost which requires a long DNS query. * There are also relations with multiple connect rounds within an IPV6 enabled system (TCL8.6.1 Linux). This arises on the following platforms: * TCL 8.5.15 on Windows Vista 32 bit * TCL 8.6.1 on Windows Vista 32 bit * TCL 8.6.1 on Linux too (Reported bei Reinhard Max) <h1>Possible reasons</h1> The error is generated by a backround flush sheduled by the writable event. The error code is stored in unreportedError. Eventually, the error message is missing in unreportedMsg. A debug trace on tclIO.c: <h2>flush $sock</h2> * tclIO.c:FlushChannel() * calls tclWinSock.c:TclOutputProc("ok"), which returns error EWOULDBLOCK * Sets flag BG_FLUSH_SCHEDULED * Clears error <h2>vwait x</h2> * tclIO.c:FlushChannel(calledFromAsyncFlush=1) * calls tclWinSock.c:TclOutputProc("ok"), which tries to write and returns error 126 * Sets statePtr->unreportedError = errorCode (126) * statePtr->unreportedMsg = msg (NULL) * Calls DiscardOutputQueued(statePtr) * Flag BG_FLUSH_SCHEDULED is cleared (no data) <h2>close $sock</h2> * tclIO.c:Tcl_Close() * > Tcl_Close calls FlushChannel(interp, chanPtr, 0) * >> FlushChannel calls CloseChannel(interp, chanPtr, errorCode) * >>> CloseChannel calls ChanClose(chanPtr, interp) * >>>> ChanClose calls tclWinSock.c:TclCloseProc(), which succeeds * >>> CloseChannel sets errorCode = statePtr->unreportedError; (126) * >>> CloseChannel calls Tcl_SetChannelErrorInterp() with NULL statePtr->unreportedMsg * >>> CloseChannel returns errorCode (126) * >> FLushChannel returns errorCode (126) * > Tcl_Close returns error: if ((flushcode != 0) || (result != 0)) { return TCL_ERROR; }
- login: "oehhar"
- mimetype: "text/plain"