summaryrefslogtreecommitdiffstats
path: root/unix
diff options
context:
space:
mode:
authorferrieux <ferrieux@users.sourceforge.net>2008-12-18 01:14:16 (GMT)
committerferrieux <ferrieux@users.sourceforge.net>2008-12-18 01:14:16 (GMT)
commita189e6bf469919f77d6e9884d112c93599363de5 (patch)
tree087ebe5ba2e9e57828831c8ad3ba41d50edb7eb4 /unix
parentcd0108cccb852eff4a8a65fa1e68297e85bc12ec (diff)
downloadtcl-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.c58
-rw-r--r--unix/tclUnixPipe.c104
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;