diff options
author | andreas_kupries <akupries@shaw.ca> | 2009-08-06 22:28:11 (GMT) |
---|---|---|
committer | andreas_kupries <akupries@shaw.ca> | 2009-08-06 22:28:11 (GMT) |
commit | f92b24a616e3a96bef3765e9bda4b66f3c7e5010 (patch) | |
tree | d37280b808ac19ae14bb5ba244e3b8616d7fd540 /generic/tclIORChan.c | |
parent | dff3fc1f53f49695e31f07d4b00ac359c4f1e728 (diff) | |
download | tcl-f92b24a616e3a96bef3765e9bda4b66f3c7e5010.zip tcl-f92b24a616e3a96bef3765e9bda4b66f3c7e5010.tar.gz tcl-f92b24a616e3a96bef3765e9bda4b66f3c7e5010.tar.bz2 |
* doc/refchan.n [Bug 2827000]: Extended the implementation of
* generic/tclIORChan.c: reflective channels (TIP 219, method
* tests/ioCmd.test: 'read'), enabling handlers to signal EAGAIN to
indicate 'no data, but not at EOF either', and other system
errors. Updated documentation, extended testsuite (New test cases
iocmd*-23.{9,10}).
Diffstat (limited to 'generic/tclIORChan.c')
-rw-r--r-- | generic/tclIORChan.c | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 554380a..5a83eca 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -15,7 +15,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIORChan.c,v 1.39 2009/02/10 22:50:09 nijtmans Exp $ + * RCS: @(#) $Id: tclIORChan.c,v 1.40 2009/08/06 22:28:11 andreas_kupries Exp $ */ #include <tclInt.h> @@ -448,6 +448,7 @@ static int InvokeTclMethod(ReflectedChannel *rcPtr, static ReflectedChannelMap * GetReflectedChannelMap(Tcl_Interp *interp); static void DeleteReflectedChannelMap(ClientData clientData, Tcl_Interp *interp); +static int ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj* resObj); /* * Global constant strings (messages). ================== @@ -1222,8 +1223,13 @@ ReflectInput( ForwardOpToOwnerThread(rcPtr, ForwardedInput, &p); if (p.base.code != TCL_OK) { - PassReceivedError(rcPtr->chan, &p); - *errorCodePtr = EINVAL; + if (p.base.code < 0) { + /* No error message, this is an errno signal. */ + *errorCodePtr = -p.base.code; + } else { + PassReceivedError(rcPtr->chan, &p); + *errorCodePtr = EINVAL; + } p.input.toRead = -1; } else { *errorCodePtr = EOK; @@ -1238,6 +1244,14 @@ ReflectInput( toReadObj = Tcl_NewIntObj(toRead); if (InvokeTclMethod(rcPtr, "read", toReadObj, NULL, &resObj)!=TCL_OK) { + int code = ErrnoReturn (rcPtr, resObj); + + if (code < 0) { + Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */ + *errorCodePtr = -code; + return -1; + } + Tcl_SetChannelError(rcPtr->chan, resObj); Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */ *errorCodePtr = EINVAL; @@ -2270,6 +2284,53 @@ InvokeTclMethod( /* *---------------------------------------------------------------------- * + * ErrnoReturn -- + * + * Checks a method error result if it returned an 'errno'. + * + * Results: + * The negative errno found in the error result, or 0. + * + * Side effects: + * None. + * + * Users: + * Currently only ReflectInput(), to enable the signaling of EAGAIN. + * by non-blocking channels at buffer-empty, but not EOF. + * + *---------------------------------------------------------------------- + */ + +static int +ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj* resObj) +{ + int code; + Tcl_InterpState sr; /* State of handler interp */ + + if (!rcPtr->interp) { + return 0; + } + + sr = Tcl_SaveInterpState(rcPtr->interp, 0 /* Dummy */); + UnmarshallErrorResult(rcPtr->interp, resObj); + + resObj = Tcl_GetObjResult(rcPtr->interp); + + if (((Tcl_GetIntFromObj(rcPtr->interp, resObj, &code) != TCL_OK) || (code >= 0))) { + if (strcmp ("EAGAIN",Tcl_GetString(resObj)) == 0) { + code = -11; + } else { + code = 0; + } + } + + Tcl_RestoreInterpState(rcPtr->interp, sr); + return code; +} + +/* + *---------------------------------------------------------------------- + * * GetReflectedChannelMap -- * * Gets and potentially initializes the reflected channel map for an @@ -2759,7 +2820,13 @@ ForwardProc( Tcl_Obj *toReadObj = Tcl_NewIntObj(paramPtr->input.toRead); if (InvokeTclMethod(rcPtr, "read", toReadObj, NULL, &resObj)!=TCL_OK){ - ForwardSetObjError(paramPtr, resObj); + int code = ErrnoReturn (rcPtr, resObj); + + if (code < 0) { + paramPtr->base.code = code; + } else { + ForwardSetObjError(paramPtr, resObj); + } paramPtr->input.toRead = -1; } else { /* |