Tcl Source Code

Check-in [7a8b871fc7]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:First draft of using buffer moves in place of buffer copies to create an efficient [chan copy].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dgp-move-buffers
Files: files | file ages | folders
SHA1: 7a8b871fc7e9c36ca807be110defe34195abf0f0
User & Date: dgp 2014-07-09 14:44:13
Context
2014-07-22
20:27
merge trunk check-in: 4bfdb8139c user: dgp tags: dgp-move-buffers
2014-07-09
14:44
First draft of using buffer moves in place of buffer copies to create an efficient [chan copy]. check-in: 7a8b871fc7 user: dgp tags: dgp-move-buffers
2014-07-08
13:45
The write and flush operations of reflected transforms ([chan push]) have been converting all lower ... check-in: cedfcfd1b5 user: dgp tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclIO.c.

178
179
180
181
182
183
184

185
186
187
188
189
190
191
static int		CloseChannel(Tcl_Interp *interp, Channel *chanPtr,
			    int errorCode);
static int		CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr,
			    int errorCode, int flags);
static int		CloseWrite(Tcl_Interp *interp, Channel *chanPtr);
static void		CommonGetsCleanup(Channel *chanPtr);
static int		CopyData(CopyState *csPtr, int mask);

static void		CopyEventProc(ClientData clientData, int mask);
static void		CreateScriptRecord(Tcl_Interp *interp,
			    Channel *chanPtr, int mask, Tcl_Obj *scriptPtr);
static void		DeleteChannelTable(ClientData clientData,
			    Tcl_Interp *interp);
static void		DeleteScriptRecord(Tcl_Interp *interp,
			    Channel *chanPtr, int mask);







>







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
static int		CloseChannel(Tcl_Interp *interp, Channel *chanPtr,
			    int errorCode);
static int		CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr,
			    int errorCode, int flags);
static int		CloseWrite(Tcl_Interp *interp, Channel *chanPtr);
static void		CommonGetsCleanup(Channel *chanPtr);
static int		CopyData(CopyState *csPtr, int mask);
static int		MoveBytes(CopyState *csPtr);
static void		CopyEventProc(ClientData clientData, int mask);
static void		CreateScriptRecord(Tcl_Interp *interp,
			    Channel *chanPtr, int mask, Tcl_Obj *scriptPtr);
static void		DeleteChannelTable(ClientData clientData,
			    Tcl_Interp *interp);
static void		DeleteScriptRecord(Tcl_Interp *interp,
			    Channel *chanPtr, int mask);
8774
8775
8776
8777
8778
8779
8780

8781
8782
8783
8784
8785
8786
8787
{
    Channel *inPtr = (Channel *) inChan;
    Channel *outPtr = (Channel *) outChan;
    ChannelState *inStatePtr, *outStatePtr;
    int readFlags, writeFlags;
    CopyState *csPtr;
    int nonBlocking = (cmdPtr) ? CHANNEL_NONBLOCKING : 0;


    inStatePtr = inPtr->state;
    outStatePtr = outPtr->state;

    if (BUSY_STATE(inStatePtr, TCL_READABLE)) {
	if (interp) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(







>







8775
8776
8777
8778
8779
8780
8781
8782
8783
8784
8785
8786
8787
8788
8789
{
    Channel *inPtr = (Channel *) inChan;
    Channel *outPtr = (Channel *) outChan;
    ChannelState *inStatePtr, *outStatePtr;
    int readFlags, writeFlags;
    CopyState *csPtr;
    int nonBlocking = (cmdPtr) ? CHANNEL_NONBLOCKING : 0;
    int moveBytes;

    inStatePtr = inPtr->state;
    outStatePtr = outPtr->state;

    if (BUSY_STATE(inStatePtr, TCL_READABLE)) {
	if (interp) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
8824
8825
8826
8827
8828
8829
8830














8831
8832
8833
8834
8835
8836
8837
8838
8839
8840
8841
8842
8843
8844
8845
8846
8847
8848
8849
8850
8851
8852




8853
8854
8855
8856
8857
8858
8859
    /*
     * Make sure the output side is unbuffered.
     */

    outStatePtr->flags = (outStatePtr->flags & ~CHANNEL_LINEBUFFERED)
	    | CHANNEL_UNBUFFERED;















    /*
     * Allocate a new CopyState to maintain info about the current copy in
     * progress. This structure will be deallocated when the copy is
     * completed.
     */

    csPtr = ckalloc(sizeof(CopyState) + inStatePtr->bufSize);
    csPtr->bufSize = inStatePtr->bufSize;
    csPtr->readPtr = inPtr;
    csPtr->writePtr = outPtr;
    csPtr->readFlags = readFlags;
    csPtr->writeFlags = writeFlags;
    csPtr->toRead = toRead;
    csPtr->total = (Tcl_WideInt) 0;
    csPtr->interp = interp;
    if (cmdPtr) {
	Tcl_IncrRefCount(cmdPtr);
    }
    csPtr->cmdPtr = cmdPtr;

    inStatePtr->csPtrR  = csPtr;
    outStatePtr->csPtrW = csPtr;





    /*
     * Special handling of -size 0 async transfers, so that the -command is
     * still called asynchronously.
     */

    if ((nonBlocking == CHANNEL_NONBLOCKING) && (toRead == 0)) {







>
>
>
>
>
>
>
>
>
>
>
>
>
>






|
|














>
>
>
>







8826
8827
8828
8829
8830
8831
8832
8833
8834
8835
8836
8837
8838
8839
8840
8841
8842
8843
8844
8845
8846
8847
8848
8849
8850
8851
8852
8853
8854
8855
8856
8857
8858
8859
8860
8861
8862
8863
8864
8865
8866
8867
8868
8869
8870
8871
8872
8873
8874
8875
8876
8877
8878
8879
    /*
     * Make sure the output side is unbuffered.
     */

    outStatePtr->flags = (outStatePtr->flags & ~CHANNEL_LINEBUFFERED)
	    | CHANNEL_UNBUFFERED;

    /*
     * Very strict set of conditions where we know we can just move bytes
     * from input channel to output channel with no transformation or even
     * examination of the bytes themselves.
     * TODO: Find ways to relax this.
     */

    moveBytes = inStatePtr->inEofChar == '\0'	/* No eofChar to stop input */
	    && inStatePtr->inputTranslation == TCL_TRANSLATE_LF
	    && outStatePtr->outputTranslation == TCL_TRANSLATE_LF
	    && inStatePtr->encoding == NULL
	    && outStatePtr->encoding == NULL
	    && !nonBlocking;	/* First draft do only blocking case */

    /*
     * Allocate a new CopyState to maintain info about the current copy in
     * progress. This structure will be deallocated when the copy is
     * completed.
     */

    csPtr = ckalloc(sizeof(CopyState) + !moveBytes * inStatePtr->bufSize);
    csPtr->bufSize = !moveBytes * inStatePtr->bufSize;
    csPtr->readPtr = inPtr;
    csPtr->writePtr = outPtr;
    csPtr->readFlags = readFlags;
    csPtr->writeFlags = writeFlags;
    csPtr->toRead = toRead;
    csPtr->total = (Tcl_WideInt) 0;
    csPtr->interp = interp;
    if (cmdPtr) {
	Tcl_IncrRefCount(cmdPtr);
    }
    csPtr->cmdPtr = cmdPtr;

    inStatePtr->csPtrR  = csPtr;
    outStatePtr->csPtrW = csPtr;

    if (moveBytes) {
	return MoveBytes(csPtr);
    }

    /*
     * Special handling of -size 0 async transfers, so that the -command is
     * still called asynchronously.
     */

    if ((nonBlocking == CHANNEL_NONBLOCKING) && (toRead == 0)) {
8880
8881
8882
8883
8884
8885
8886































































































8887
8888
8889
8890
8891
8892
8893
 *	Returns TCL_OK on success, else TCL_ERROR.
 *
 * Side effects:
 *	Moves data between channels, may create channel handlers.
 *
 *----------------------------------------------------------------------
 */
































































































static int
CopyData(
    CopyState *csPtr,		/* State of copy operation. */
    int mask)			/* Current channel event flags. */
{
    Tcl_Interp *interp;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







8900
8901
8902
8903
8904
8905
8906
8907
8908
8909
8910
8911
8912
8913
8914
8915
8916
8917
8918
8919
8920
8921
8922
8923
8924
8925
8926
8927
8928
8929
8930
8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944
8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982
8983
8984
8985
8986
8987
8988
8989
8990
8991
8992
8993
8994
8995
8996
8997
8998
8999
9000
9001
9002
9003
9004
9005
9006
9007
9008
 *	Returns TCL_OK on success, else TCL_ERROR.
 *
 * Side effects:
 *	Moves data between channels, may create channel handlers.
 *
 *----------------------------------------------------------------------
 */

static int
MoveBytes(
    CopyState *csPtr)		/* State of copy operation. */
{
    ChannelState *inStatePtr = csPtr->readPtr->state;
    ChannelState *outStatePtr = csPtr->writePtr->state;
    ChannelBuffer *bufPtr = outStatePtr->curOutPtr;
    int code = TCL_OK;

    if (bufPtr && BytesLeft(bufPtr)) {
	/* If we start with unflushed bytes in the destination
	 * channel, flush them out of the way first. */

	if (0 != FlushChannel(csPtr->interp, outStatePtr->topChanPtr, 0)) {
	    code = TCL_ERROR;
	    goto done;
	}
    }

    while (csPtr->toRead != 0) {
	ChannelBuffer *bufPtr = inStatePtr->inQueueHead;
	ChannelBuffer *tail = NULL;
	int inBytes = 0;

	if (bufPtr == NULL || BytesLeft(bufPtr) == 0) {
	    /* Nothing in the input queue;  Get more input. */

	    if (0 != GetInput(inStatePtr->topChanPtr)) { 
		code = TCL_ERROR;
		break;
	    }
	    bufPtr = inStatePtr->inQueueHead;
	}

	/* Count up number of bytes waiting in the input queue */
	while (bufPtr) {
	    inBytes += BytesLeft(bufPtr);
	    tail = bufPtr;
	    if (csPtr->toRead != -1 && csPtr->toRead < inBytes) {
		/* Queue has enough bytes to complete the copy */
		break;
	    }
	    bufPtr = bufPtr->nextPtr;
	}

	if (bufPtr) {
	    /* Split the overflowing buffer in two */
	    int extra = inBytes - csPtr->toRead;

	    bufPtr = AllocChannelBuffer(extra);

	    tail->nextAdded -= extra;
	    memcpy(InsertPoint(bufPtr), InsertPoint(tail), extra);
	    bufPtr->nextAdded += extra;
	    bufPtr->nextPtr = tail->nextPtr;
	    tail->nextPtr = NULL;
	    inBytes = csPtr->toRead;
	}

	/* Update the byte counts */
	if (csPtr->toRead != -1) {
	    csPtr->toRead -= inBytes;
	}
	csPtr->total += inBytes;

	/* Move buffers from input to output channels */
	if (outStatePtr->outQueueTail) {
	    outStatePtr->outQueueTail->nextPtr = inStatePtr->inQueueHead;
	} else {
	    outStatePtr->outQueueHead = inStatePtr->inQueueHead;
	}
	outStatePtr->outQueueTail = tail;
	inStatePtr->inQueueHead = bufPtr;
	if (bufPtr == NULL) {
	    inStatePtr->inQueueTail = NULL;
	}

	/* Flush destination */
	if (0 != FlushChannel(csPtr->interp, outStatePtr->topChanPtr, 0)) {
	    code = TCL_ERROR;
	    break;
	}
	if (GotFlag(inStatePtr, CHANNEL_EOF)) {
	    break;
	}
    }

    if (code == TCL_OK) {
	Tcl_SetObjResult(csPtr->interp, Tcl_NewWideIntObj(csPtr->total));
    }
  done:
    StopCopy(csPtr);
    return code;
}

static int
CopyData(
    CopyState *csPtr,		/* State of copy operation. */
    int mask)			/* Current channel event flags. */
{
    Tcl_Interp *interp;