summaryrefslogtreecommitdiffstats
path: root/generic/tclIORChan.c
diff options
context:
space:
mode:
authorandreas_kupries <akupries@shaw.ca>2009-08-06 22:28:11 (GMT)
committerandreas_kupries <akupries@shaw.ca>2009-08-06 22:28:11 (GMT)
commitf92b24a616e3a96bef3765e9bda4b66f3c7e5010 (patch)
treed37280b808ac19ae14bb5ba244e3b8616d7fd540 /generic/tclIORChan.c
parentdff3fc1f53f49695e31f07d4b00ac359c4f1e728 (diff)
downloadtcl-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.c75
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 {
/*