Check-in [bd6ad3191b]
Not logged in

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

Overview
Comment:merge fork of 8.5 branch
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: bd6ad3191b3cd83917676ed17252f98cf1e607a2
User & Date: dgp 2014-06-03 19:57:31.483
Context
2014-06-04
16:36
Revise DiscardOutput() to account for revisions to the loop in FlushChannel() which is its only call... check-in: 2b1cda088c user: dgp tags: core-8-5-branch
2014-06-03
19:57
merge fork of 8.5 branch check-in: bd6ad3191b user: dgp tags: core-8-5-branch
17:32
Backport I/O core fixes made known by async socket work on trunk. check-in: c801a8d5cc user: dgp tags: core-8-5-branch
2014-05-31
02:30
Correct the interest masks in the Tcl_CreateFileHandler() calls in PipeWatchProc(). When we are int... check-in: 74a2238ecc user: dgp tags: core-8-5-branch
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tclIO.c.
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708

2709
2710
2711
2712
2713
2714
2715
	if (wroteSome) {
	    return errorCode;
	} else if (statePtr->outQueueHead == NULL) {
	    ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
	    (chanPtr->typePtr->watchProc)(chanPtr->instanceData,
		    statePtr->interestMask);
	} else {

	    /*
	     * When we are calledFromAsyncFlush, that means a writable
	     * state on the channel triggered the call, so we should be
	     * able to write something.  Either we did write something 
	     * and wroteSome should be set, or there was nothing left to
	     * write in this call, and we've completed the BG flush.
	     * These are the two cases above.  If we get here, that means
	     * there is some kind failure in the writable event machinery.
	     */

	    assert(!calledFromAsyncFlush);

	}
    }

    /*
     * If the channel is flagged as closed, delete it when the refCount drops
     * to zero, the output queue is empty and there is no output in the
     * current output buffer.







|
<
<
|
<
<
<
<
|
<
|
<
>







2690
2691
2692
2693
2694
2695
2696
2697


2698




2699

2700

2701
2702
2703
2704
2705
2706
2707
2708
	if (wroteSome) {
	    return errorCode;
	} else if (statePtr->outQueueHead == NULL) {
	    ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
	    (chanPtr->typePtr->watchProc)(chanPtr->instanceData,
		    statePtr->interestMask);
	} else {
	    /* TODO: If code reaches this point, it means a writable


	     * event is being handled on the channel, but the channel




	     * could not in fact be written to.  This ought not happen,

	     * but Unix pipes appear to act this way (see io-53.4).

	     * Also can imagine broken reflected channels. */
	}
    }

    /*
     * If the channel is flagged as closed, delete it when the refCount drops
     * to zero, the output queue is empty and there is no output in the
     * current output buffer.
3208
3209
3210
3211
3212
3213
3214
3215
3216

3217


3218
3219




3220
3221
3222
3223
3224
3225
3226
    /*
     * When the channel has an escape sequence driven encoding such as
     * iso2022, the terminated escape sequence must write to the buffer.
     */

    stickyError = 0;

    if ((statePtr->encoding != NULL)
	    && !(statePtr->outputEncodingFlags & TCL_ENCODING_START)

	    && (CheckChannelErrors(statePtr, TCL_WRITABLE) == 0)) {


	statePtr->outputEncodingFlags |= TCL_ENCODING_END;
	if (WriteChars(chanPtr, "", 0) < 0) {




	    stickyError = Tcl_GetErrno();
	}

	/*
	 * TIP #219, Tcl Channel Reflection API.
	 * Move an error message found in the channel bypass into the
	 * interpreter bypass. Just clear it if there is no interpreter.







|
|
>
|
>
>
|
|
>
>
>
>







3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
    /*
     * When the channel has an escape sequence driven encoding such as
     * iso2022, the terminated escape sequence must write to the buffer.
     */

    stickyError = 0;

    if (GotFlag(statePtr, TCL_WRITABLE) && (statePtr->encoding != NULL)
	    && !(statePtr->outputEncodingFlags & TCL_ENCODING_START)) {

	int code = CheckChannelErrors(statePtr, TCL_WRITABLE);

	if (code == 0) {
	    statePtr->outputEncodingFlags |= TCL_ENCODING_END;
	    code = WriteChars(chanPtr, "", 0);
	    statePtr->outputEncodingFlags &= ~TCL_ENCODING_END;
	    statePtr->outputEncodingFlags |= TCL_ENCODING_START;
	}
	if (code < 0) {
	    stickyError = Tcl_GetErrno();
	}

	/*
	 * TIP #219, Tcl Channel Reflection API.
	 * Move an error message found in the channel bypass into the
	 * interpreter bypass. Just clear it if there is no interpreter.
7642
7643
7644
7645
7646
7647
7648
7649
7650

7651
7652
7653
7654
7655
7656
7657
    /*
     * If we are flushing in the background, be sure to call FlushChannel for
     * writable events. Note that we have to discard the writable event so we
     * don't call any write handlers before the flush is complete.
     */

    if (GotFlag(statePtr, BG_FLUSH_SCHEDULED) && (mask & TCL_WRITABLE)) {
	FlushChannel(NULL, chanPtr, 1);
	mask &= ~TCL_WRITABLE;

    }

    /*
     * Add this invocation to the list of recursive invocations of
     * ChannelHandlerEventProc.
     */








|
|
>







7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
    /*
     * If we are flushing in the background, be sure to call FlushChannel for
     * writable events. Note that we have to discard the writable event so we
     * don't call any write handlers before the flush is complete.
     */

    if (GotFlag(statePtr, BG_FLUSH_SCHEDULED) && (mask & TCL_WRITABLE)) {
	if (0 == FlushChannel(NULL, chanPtr, 1)) {
	    mask &= ~TCL_WRITABLE;
	}
    }

    /*
     * Add this invocation to the list of recursive invocations of
     * ChannelHandlerEventProc.
     */

Changes to tests/io.test.
7116
7117
7118
7119
7120
7121
7122

7123
7124
7125
7126
7127
7128




7129
7130
7131
7132
7133
7134
7135

7136
7137
7138
7139
7140
7141
7142
} "ready line1 line2 {done\n}"
test io-53.4 {CopyData: background write overflow} {stdio unix openpipe fileevent fcopy} {
    set big bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n
    variable x
    for {set x 0} {$x < 12} {incr x} {
	append big $big
    }

    file delete $path(pipe)
    set f1 [open $path(pipe) w]
    puts $f1 {
	puts ready
	fcopy stdin stdout -command { set x }
	vwait x




    }
    close $f1
    set f1 [open "|[list [interpreter] $path(pipe)]" r+]
    set result [gets $f1]
    fconfigure $f1 -blocking 0
    puts $f1 $big
    flush $f1

    set result ""
    fileevent $f1 read [namespace code {
	append result [read $f1 1024]
	if {[string length $result] >= [string length $big]} {
	    set x done
	}
    }]







>






>
>
>
>







>







7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
} "ready line1 line2 {done\n}"
test io-53.4 {CopyData: background write overflow} {stdio unix openpipe fileevent fcopy} {
    set big bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n
    variable x
    for {set x 0} {$x < 12} {incr x} {
	append big $big
    }
#    file delete $path(test1)
    file delete $path(pipe)
    set f1 [open $path(pipe) w]
    puts $f1 {
	puts ready
	fcopy stdin stdout -command { set x }
	vwait x
#	set f [open $path(test1) w]
#	fconfigure $f -translation lf
#	puts $f "done"
#	close $f
    }
    close $f1
    set f1 [open "|[list [interpreter] $path(pipe)]" r+]
    set result [gets $f1]
    fconfigure $f1 -blocking 0
    puts $f1 $big
    flush $f1
    after 500
    set result ""
    fileevent $f1 read [namespace code {
	append result [read $f1 1024]
	if {[string length $result] >= [string length $big]} {
	    set x done
	}
    }]
Changes to unix/tclUnixPipe.c.
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
{
    PipeState *psPtr = (PipeState *) instanceData;
    int newmask;

    if (psPtr->inFile) {
	newmask = mask & (TCL_READABLE | TCL_EXCEPTION);
	if (newmask) {
	    Tcl_CreateFileHandler(GetFd(psPtr->inFile), newmask,
		    (Tcl_FileProc *) Tcl_NotifyChannel,
		    (ClientData) psPtr->channel);
	} else {
	    Tcl_DeleteFileHandler(GetFd(psPtr->inFile));
	}
    }
    if (psPtr->outFile) {
	newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION);
	if (newmask) {
	    Tcl_CreateFileHandler(GetFd(psPtr->outFile), newmask,
		    (Tcl_FileProc *) Tcl_NotifyChannel,
		    (ClientData) psPtr->channel);
	} else {
	    Tcl_DeleteFileHandler(GetFd(psPtr->outFile));
	}
    }
}







|









|







1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
{
    PipeState *psPtr = (PipeState *) instanceData;
    int newmask;

    if (psPtr->inFile) {
	newmask = mask & (TCL_READABLE | TCL_EXCEPTION);
	if (newmask) {
	    Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask,
		    (Tcl_FileProc *) Tcl_NotifyChannel,
		    (ClientData) psPtr->channel);
	} else {
	    Tcl_DeleteFileHandler(GetFd(psPtr->inFile));
	}
    }
    if (psPtr->outFile) {
	newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION);
	if (newmask) {
	    Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask,
		    (Tcl_FileProc *) Tcl_NotifyChannel,
		    (ClientData) psPtr->channel);
	} else {
	    Tcl_DeleteFileHandler(GetFd(psPtr->outFile));
	}
    }
}
Changes to win/tclWinSock.c.
1235
1236
1237
1238
1239
1240
1241


1242
1243

1244
1245
1246
1247
1248

1249
1250
1251
1252
1253
1254
1255
     * Be sure to disable event servicing so we are truly modal.
     */

    oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);

    /*
     * Reset WSAAsyncSelect so we have a fresh set of events pending.


     */


    SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT,
	    (LPARAM) infoPtr);

    SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
	    (LPARAM) infoPtr);


    while (1) {
	if (infoPtr->lastError) {
	    *errorCodePtr = infoPtr->lastError;
	    result = 0;
	    break;
	} else if (infoPtr->readyEvents & events) {







>
>


>
|
|
|
|
|
>







1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
     * Be sure to disable event servicing so we are truly modal.
     */

    oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);

    /*
     * Reset WSAAsyncSelect so we have a fresh set of events pending.
     * Don't do that if we are waiting for a connect as we may miss
     * a connect (bug 336441ed59).
     */

    if ( 0 == (events & FD_CONNECT) ) {
        SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT,
                (LPARAM) infoPtr);
    
        SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
                (LPARAM) infoPtr);
    }

    while (1) {
	if (infoPtr->lastError) {
	    *errorCodePtr = infoPtr->lastError;
	    result = 0;
	    break;
	} else if (infoPtr->readyEvents & events) {
2405
2406
2407
2408
2409
2410
2411




2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
	}
	SetEvent(tsdPtr->socketListLock);
	break;

    case SOCKET_SELECT:
	infoPtr = (SocketInfo *) lParam;
	if (wParam == SELECT) {




	    WSAAsyncSelect(infoPtr->socket, hwnd,
		    SOCKET_MESSAGE, infoPtr->selectEvents);
	} else {
	    /*
	     * Clear the selection mask
	     */

	    WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0);
	}
	break;

    case SOCKET_TERMINATE:







>
>
>
>




|







2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
	}
	SetEvent(tsdPtr->socketListLock);
	break;

    case SOCKET_SELECT:
	infoPtr = (SocketInfo *) lParam;
	if (wParam == SELECT) {
            /*
             * Start notification by windows messages on socket events
             */

	    WSAAsyncSelect(infoPtr->socket, hwnd,
		    SOCKET_MESSAGE, infoPtr->selectEvents);
	} else {
	    /*
	     * UNSELECT: Clear the selection mask
	     */

	    WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0);
	}
	break;

    case SOCKET_TERMINATE: