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/tclUnixPipe.c | |
| 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/tclUnixPipe.c')
| -rw-r--r-- | unix/tclUnixPipe.c | 104 | 
1 files changed, 98 insertions, 6 deletions
| 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; | 
