Tcl Source Code

Check-in [ef3818afcd]
Login

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

Overview
Comment:Simplify reflected channels. Instead of having two modes of Close operations and the need to choose between them with a special value of the methods field, when the initialize pass fails for some reason, simply do not create the channel so there's nothing that needs closing. Then the methods field no longer holds anything used, so eliminate it. All the methods checking is done by [chan create].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: ef3818afcdf3302f5fbd8325ac22b645782b8388
User & Date: dgp 2014-04-17 16:05:06
Context
2014-04-17
17:55
Reflected channels. Keep a set of method names cached so we don't create new each operation, and we... check-in: 4c7df62128 user: dgp tags: core-8-5-branch
16:05
Simplify reflected channels. Instead of having two modes of Close operations and the need to choose ... check-in: ef3818afcd user: dgp tags: core-8-5-branch
2014-04-16
15:37
Repair new test so all parts will be effective. check-in: ff8ab70e08 user: dgp tags: core-8-5-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclIORChan.c.

88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
				 * interpreter/thread containing its Tcl
				 * command is gone.
				 */
#ifdef TCL_THREADS
    Tcl_ThreadId thread;	/* Thread the 'interp' belongs to. */
#endif
    Tcl_Obj *cmd;		/* Callback command prefix */
    int methods;		/* Bitmask of supported methods */

    /*
     * NOTE (9): Should we have predefined shared literals for the method
     * names?
     */

    int mode;			/* Mask of R/W mode */







<







88
89
90
91
92
93
94

95
96
97
98
99
100
101
				 * interpreter/thread containing its Tcl
				 * command is gone.
				 */
#ifdef TCL_THREADS
    Tcl_ThreadId thread;	/* Thread the 'interp' belongs to. */
#endif
    Tcl_Obj *cmd;		/* Callback command prefix */


    /*
     * NOTE (9): Should we have predefined shared literals for the method
     * names?
     */

    int mode;			/* Mask of R/W mode */
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/*
 * Global constant strings (messages). ==================
 * These string are used directly as bypass errors, thus they have to be valid
 * Tcl lists where the last element is the message itself. Hence the
 * list-quoting to keep the words of the message together. See also [x].
 */

static const char *msg_read_unsup = "{read not supported by Tcl driver}";
static const char *msg_read_toomuch = "{read delivered more than requested}";
static const char *msg_write_unsup = "{write not supported by Tcl driver}";
static const char *msg_write_toomuch = "{write wrote more than requested}";
static const char *msg_write_nothing = "{write wrote nothing}";
static const char *msg_seek_beforestart = "{Tried to seek before origin}";
#ifdef TCL_THREADS
static const char *msg_send_originlost = "{Channel thread lost}";
static const char *msg_send_dstlost    = "{Owner lost}";
#endif /* TCL_THREADS */







<

<







431
432
433
434
435
436
437

438

439
440
441
442
443
444
445
/*
 * Global constant strings (messages). ==================
 * These string are used directly as bypass errors, thus they have to be valid
 * Tcl lists where the last element is the message itself. Hence the
 * list-quoting to keep the words of the message together. See also [x].
 */


static const char *msg_read_toomuch = "{read delivered more than requested}";

static const char *msg_write_toomuch = "{write wrote more than requested}";
static const char *msg_write_nothing = "{write wrote nothing}";
static const char *msg_seek_beforestart = "{Tried to seek before origin}";
#ifdef TCL_THREADS
static const char *msg_send_originlost = "{Channel thread lost}";
static const char *msg_send_dstlost    = "{Owner lost}";
#endif /* TCL_THREADS */
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564

    /*
     * Now create the channel.
     */

    rcId = NextHandle();
    rcPtr = NewReflectedChannel(interp, cmdObj, mode, rcId);
    chan = Tcl_CreateChannel(&tclRChannelType, TclGetString(rcId), rcPtr,
	    mode);
    rcPtr->chan = chan;
    Tcl_Preserve(chan);
    chanPtr = (Channel *) chan;

    /*
     * Invoke 'initialize' and validate that the handler is present and ok.
     * Squash the channel if not.
     *
     * Note: The conversion of 'mode' back into a Tcl_Obj ensures that
     * 'initialize' is invoked with canonical mode names, and no







<
<
<
<
<







543
544
545
546
547
548
549





550
551
552
553
554
555
556

    /*
     * Now create the channel.
     */

    rcId = NextHandle();
    rcPtr = NewReflectedChannel(interp, cmdObj, mode, rcId);






    /*
     * Invoke 'initialize' and validate that the handler is present and ok.
     * Squash the channel if not.
     *
     * Note: The conversion of 'mode' back into a Tcl_Obj ensures that
     * 'initialize' is invoked with canonical mode names, and no
653
654
655
656
657
658
659


660


661
662
663
664
665
666
667

    Tcl_ResetResult(interp);

    /*
     * Everything is fine now.
     */



    rcPtr->methods = methods;



    if ((methods & NULLABLE_METHODS) != NULLABLE_METHODS) {
	/*
	 * Some of the nullable methods are not supported. We clone the
	 * channel type, null the associated C functions, and use the result
	 * as the actual channel type.
	 */







>
>
|
>
>







645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663

    Tcl_ResetResult(interp);

    /*
     * Everything is fine now.
     */

    chan = Tcl_CreateChannel(&tclRChannelType, TclGetString(rcId), rcPtr,
	    mode);
    rcPtr->chan = chan;
    Tcl_Preserve(chan);
    chanPtr = (Channel *) chan;

    if ((methods & NULLABLE_METHODS) != NULLABLE_METHODS) {
	/*
	 * Some of the nullable methods are not supported. We clone the
	 * channel type, null the associated C functions, and use the result
	 * as the actual channel type.
	 */
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
     * Return handle as result of command.
     */

    Tcl_SetObjResult(interp, rcId);
    return TCL_OK;

 error:
    /*
     * Signal to ReflectClose to not call 'finalize'.
     */

    rcPtr->methods = 0;
    Tcl_Close(interp, chan);
    return TCL_ERROR;

#undef MODE
#undef CMD
}

/*







<
<
<
|
|
<







712
713
714
715
716
717
718



719
720

721
722
723
724
725
726
727
     * Return handle as result of command.
     */

    Tcl_SetObjResult(interp, rcId);
    return TCL_OK;

 error:



    Tcl_DecrRefCount(rcPtr->cmd);
    ckfree((char*) rcPtr);

    return TCL_ERROR;

#undef MODE
#undef CMD
}

/*
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
	}
#endif

        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
	return EOK;
    }

    /*
     * -- No -- ASSERT rcPtr->methods & FLAG(METH_FINAL)
     *
     * A cleaned method mask here implies that the channel creation was
     * aborted, and "finalize" must not be called.
     */

    if (rcPtr->methods == 0) {
        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
	return EOK;
    }

    /*
     * Are we in the correct thread?
     */

#ifdef TCL_THREADS
    if (rcPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;







<
<
<
<
<
<
<
<
<
<
<
<







1056
1057
1058
1059
1060
1061
1062












1063
1064
1065
1066
1067
1068
1069
	}
#endif

        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
	return EOK;
    }













    /*
     * Are we in the correct thread?
     */

#ifdef TCL_THREADS
    if (rcPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
{
    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData;
    Tcl_Obj *toReadObj;
    int bytec;			/* Number of returned bytes */
    unsigned char *bytev;	/* Array of returned bytes */
    Tcl_Obj *resObj;		/* Result data for 'read' */

    /*
     * The following check can be done before thread redirection, because we
     * are reading from an item which is readonly, i.e. will never change
     * during the lifetime of the channel.
     */

    if (!(rcPtr->methods & FLAG(METH_READ))) {
	SetChannelErrorStr(rcPtr->chan, msg_read_unsup);
	*errorCodePtr = EINVAL;
	return -1;
    }

    /*
     * Are we in the correct thread?
     */

#ifdef TCL_THREADS
    if (rcPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;







<
<
<
<
<
<
<
<
<
<
<
<







1151
1152
1153
1154
1155
1156
1157












1158
1159
1160
1161
1162
1163
1164
{
    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData;
    Tcl_Obj *toReadObj;
    int bytec;			/* Number of returned bytes */
    unsigned char *bytev;	/* Array of returned bytes */
    Tcl_Obj *resObj;		/* Result data for 'read' */













    /*
     * Are we in the correct thread?
     */

#ifdef TCL_THREADS
    if (rcPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
    int *errorCodePtr)
{
    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData;
    Tcl_Obj *bufObj;
    Tcl_Obj *resObj;		/* Result data for 'write' */
    int written;

    /*
     * The following check can be done before thread redirection, because we
     * are reading from an item which is readonly, i.e. will never change
     * during the lifetime of the channel.
     */

    if (!(rcPtr->methods & FLAG(METH_WRITE))) {
	SetChannelErrorStr(rcPtr->chan, msg_write_unsup);
	*errorCodePtr = EINVAL;
	return -1;
    }

    /*
     * Are we in the correct thread?
     */

#ifdef TCL_THREADS
    if (rcPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;







<
<
<
<
<
<
<
<
<
<
<
<







1254
1255
1256
1257
1258
1259
1260












1261
1262
1263
1264
1265
1266
1267
    int *errorCodePtr)
{
    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData;
    Tcl_Obj *bufObj;
    Tcl_Obj *resObj;		/* Result data for 'write' */
    int written;













    /*
     * Are we in the correct thread?
     */

#ifdef TCL_THREADS
    if (rcPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
ReflectWatch(
    ClientData clientData,
    int mask)
{
    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData;
    Tcl_Obj *maskObj;

    /* ASSERT rcPtr->methods & FLAG(METH_WATCH) */

    /*
     * We restrict the interest to what the channel can support. IOW there
     * will never be write events for a channel which is not writable.
     * Analoguously for read events and non-readable channels.
     */

    mask &= rcPtr->mode;







<
<







1476
1477
1478
1479
1480
1481
1482


1483
1484
1485
1486
1487
1488
1489
ReflectWatch(
    ClientData clientData,
    int mask)
{
    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData;
    Tcl_Obj *maskObj;



    /*
     * We restrict the interest to what the channel can support. IOW there
     * will never be write events for a channel which is not writable.
     * Analoguously for read events and non-readable channels.
     */

    mask &= rcPtr->mode;
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
    Tcl_Obj *handleObj)
{
    ReflectedChannel *rcPtr;

    rcPtr = (ReflectedChannel *) ckalloc(sizeof(ReflectedChannel));

    /* rcPtr->chan: Assigned by caller. Dummy data here. */
    /* rcPtr->methods: Assigned by caller. Dummy data here. */

    rcPtr->chan = NULL;
    rcPtr->methods = 0;
    rcPtr->interp = interp;
#ifdef TCL_THREADS
    rcPtr->thread = Tcl_GetCurrentThread();
#endif
    rcPtr->mode = mode;
    rcPtr->interest = 0;		/* Initially no interest registered */








<


<







1958
1959
1960
1961
1962
1963
1964

1965
1966

1967
1968
1969
1970
1971
1972
1973
    Tcl_Obj *handleObj)
{
    ReflectedChannel *rcPtr;

    rcPtr = (ReflectedChannel *) ckalloc(sizeof(ReflectedChannel));

    /* rcPtr->chan: Assigned by caller. Dummy data here. */


    rcPtr->chan = NULL;

    rcPtr->interp = interp;
#ifdef TCL_THREADS
    rcPtr->thread = Tcl_GetCurrentThread();
#endif
    rcPtr->mode = mode;
    rcPtr->interest = 0;		/* Initially no interest registered */