diff options
author | ferrieux <ferrieux@users.sourceforge.net> | 2008-12-18 01:14:16 (GMT) |
---|---|---|
committer | ferrieux <ferrieux@users.sourceforge.net> | 2008-12-18 01:14:16 (GMT) |
commit | a189e6bf469919f77d6e9884d112c93599363de5 (patch) | |
tree | 087ebe5ba2e9e57828831c8ad3ba41d50edb7eb4 /unix | |
parent | cd0108cccb852eff4a8a65fa1e68297e85bc12ec (diff) | |
download | tcl-a189e6bf469919f77d6e9884d112c93599363de5.zip tcl-a189e6bf469919f77d6e9884d112c93599363de5.tar.gz tcl-a189e6bf469919f77d6e9884d112c93599363de5.tar.bz2 |
TIP #332 IMPLEMENTATION - Half-Close for Bidirectional Channels
Diffstat (limited to 'unix')
-rw-r--r-- | unix/tclUnixChan.c | 58 | ||||
-rw-r--r-- | unix/tclUnixPipe.c | 104 |
2 files changed, 154 insertions, 8 deletions
diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index 653f223..51781c0 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixChan.c,v 1.96 2008/10/26 12:45:04 dkf Exp $ + * RCS: @(#) $Id: tclUnixChan.c,v 1.97 2008/12/18 01:14:16 ferrieux Exp $ */ #include "tclInt.h" /* Internal definitions for Tcl. */ @@ -218,6 +218,9 @@ static void TcpAccept(ClientData data, int mask); static int TcpBlockModeProc(ClientData data, int mode); static int TcpCloseProc(ClientData instanceData, Tcl_Interp *interp); +static int TcpClose2Proc(ClientData instanceData, + Tcl_Interp *interp, + int flags); static int TcpGetHandleProc(ClientData instanceData, int direction, ClientData *handlePtr); static int TcpGetOptionProc(ClientData instanceData, @@ -318,7 +321,7 @@ static Tcl_ChannelType tcpChannelType = { TcpGetOptionProc, /* Get option proc. */ TcpWatchProc, /* Initialize notifier. */ TcpGetHandleProc, /* Get OS handles out of channel. */ - NULL, /* close2proc. */ + TcpClose2Proc, /* Close2 proc. */ TcpBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ @@ -2018,6 +2021,57 @@ TcpCloseProc( /* *---------------------------------------------------------------------- * + * TcpClose2Proc -- + * + * This function is called by the generic IO level to perform the channel + * type specific part of a half-close: namely, a shutdown() on a socket. + * + * Results: + * 0 if successful, the value of errno if failed. + * + * Side effects: + * Shuts down one side of the socket. + * + *---------------------------------------------------------------------- + */ + +static int +TcpClose2Proc( + ClientData instanceData, /* The socket to close. */ + Tcl_Interp *interp, /* For error reporting. */ + int flags) /* Flags that indicate which side to close. */ +{ + TcpState *statePtr = (TcpState *) instanceData; + int errorCode = 0; + int sd; + + /* + * Shutdown the OS socket handle. + */ + switch(flags) + { + case TCL_CLOSE_READ: + sd=SHUT_RD; + break; + case TCL_CLOSE_WRITE: + sd=SHUT_WR; + break; + default: + if (interp) { + Tcl_AppendResult(interp, "Socket close2proc called bidirectionally", NULL); + } + return TCL_ERROR; + } + if (shutdown(statePtr->fd,sd)<0) { + errorCode = errno; + } + + return errorCode; +} + +/* + *---------------------------------------------------------------------- + * * TcpGetOptionProc -- * * Computes an option value for a TCP socket based channel, or a list of diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c index 967d633..0381764 100644 --- a/unix/tclUnixPipe.c +++ b/unix/tclUnixPipe.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixPipe.c,v 1.45 2008/12/12 16:07:18 ferrieux Exp $ + * RCS: @(#) $Id: tclUnixPipe.c,v 1.46 2008/12/18 01:14:17 ferrieux Exp $ */ #include "tclInt.h" @@ -51,8 +51,10 @@ typedef struct PipeState { */ static int PipeBlockModeProc(ClientData instanceData, int mode); -static int PipeCloseProc(ClientData instanceData, - Tcl_Interp *interp); +static int PipeClose2Proc(ClientData instanceData, + Tcl_Interp *interp, int flags); +/* static int PipeCloseProc(ClientData instanceData, + Tcl_Interp *interp); */ static int PipeGetHandleProc(ClientData instanceData, int direction, ClientData *handlePtr); static int PipeInputProc(ClientData instanceData, char *buf, @@ -71,7 +73,7 @@ static int SetupStdFile(TclFile file, int type); static Tcl_ChannelType pipeChannelType = { "pipe", /* Type name. */ TCL_CHANNEL_VERSION_5, /* v5 channel */ - PipeCloseProc, /* Close proc. */ + TCL_CLOSE2PROC, /* Close proc. */ PipeInputProc, /* Input proc. */ PipeOutputProc, /* Output proc. */ NULL, /* Seek proc. */ @@ -79,7 +81,7 @@ static Tcl_ChannelType pipeChannelType = { NULL, /* Get option proc. */ PipeWatchProc, /* Initialize notifier. */ PipeGetHandleProc, /* Get OS handles out of channel. */ - NULL, /* close2proc. */ + PipeClose2Proc, /* close2proc. */ PipeBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ @@ -908,7 +910,96 @@ PipeBlockModeProc( /* *---------------------------------------------------------------------- * - * PipeCloseProc -- + * PipeClose2Proc + * + * This function is invoked by the generic IO level to perform + * pipeline-type-specific half or full-close. + * + * Results: + * 0 on success, errno otherwise. + * + * Side effects: + * Closes the command pipeline channel. + * + *---------------------------------------------------------------------- + */ + +static int +PipeClose2Proc( + ClientData instanceData, /* The pipe to close. */ + Tcl_Interp *interp, /* For error reporting. */ + int flags) /* Flags that indicate which side to close. */ +{ + PipeState *pipePtr= (PipeState *) instanceData; + Tcl_Channel errChan; + int errorCode, result; + + errorCode = 0; + result = 0; + + if (((!flags)||(flags & TCL_CLOSE_READ)) && (pipePtr->inFile != NULL)) { + if (TclpCloseFile(pipePtr->inFile) < 0) { + errorCode = errno; + } else { + pipePtr->inFile=NULL; + } + } + if (((!flags)||(flags & TCL_CLOSE_WRITE)) && (pipePtr->outFile != NULL) && (errorCode == 0)) { + if (TclpCloseFile(pipePtr->outFile) < 0) { + errorCode = errno; + } else { + pipePtr->outFile=NULL; + } + } + + /* if half-closing, stop here. */ + if (flags) { + return errorCode; + } + + if (pipePtr->isNonBlocking || TclInExit()) { + /* + * If the channel is non-blocking or Tcl is being cleaned up, just + * detach the children PIDs, reap them (important if we are in a + * dynamic load module), and discard the errorFile. + */ + + Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr); + Tcl_ReapDetachedProcs(); + + if (pipePtr->errorFile) { + TclpCloseFile(pipePtr->errorFile); + } + } else { + /* + * Wrap the error file into a channel and give it to the cleanup + * routine. + */ + + if (pipePtr->errorFile) { + errChan = Tcl_MakeFileChannel( + (ClientData) INT2PTR(GetFd(pipePtr->errorFile)), TCL_READABLE); + } else { + errChan = NULL; + } + result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr, + errChan); + } + + if (pipePtr->numPids != 0) { + ckfree((char *) pipePtr->pidPtr); + } + ckfree((char *) pipePtr); + if (errorCode == 0) { + return result; + } + return errorCode; +} + +/* + *---------------------------------------------------------------------- + * + * PipeCloseProc -- OBSOLETE * * This function is invoked by the generic IO level to perform * channel-type-specific cleanup when a command pipeline channel is @@ -936,6 +1027,7 @@ PipeCloseProc( errorCode = 0; result = 0; pipePtr = (PipeState *) instanceData; + if (pipePtr->inFile) { if (TclpCloseFile(pipePtr->inFile) < 0) { errorCode = errno; |