Tcl package Thread source code

Check-in [bb825fdd0c]
Login

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

Overview
Comment:add -command option to [thread::send]
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | pyk-sendcmd
Files: files | file ages | folders
SHA3-256:bb825fdd0c129732ef7b4f5b23b36940650abfb670014cf397b33f1a9fdfa9c3
User & Date: pooryorick 2018-07-17 21:07:15
References
2018-12-03
15:12
Integrate [bb825fdd0c129732]: add -command option to [thread::send] Leaf check-in: 2ac38ca6c1 user: jan.nijtmans tags: trunk
Context
2018-12-03
15:12
Integrate [bb825fdd0c129732]: add -command option to [thread::send] Leaf check-in: 2ac38ca6c1 user: jan.nijtmans tags: trunk
2018-07-17
21:07
add -command option to [thread::send] Closed-Leaf check-in: bb825fdd0c user: pooryorick tags: pyk-sendcmd
11:31
merge 2.8 check-in: b58409de1c user: sebres tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/threadCmd.c.

16
17
18
19
20
21
22

23
24
25
26
27
28
29
...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
...
203
204
205
206
207
208
209

210
211
212
213
214
215
216
...
932
933
934
935
936
937
938






939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
...
967
968
969
970
971
972
973



974
975
976
977
978
979
980
...
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
....
1005
1006
1007
1008
1009
1010
1011



1012

1013
1014
1015
1016

1017
1018
1019
1020
1021
1022
1023
....
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696

1697

1698
1699
1700
1701
1702
























1703
1704
1705
1706
1707
1708
1709
....
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
....
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
....
3263
3264
3265
3266
3267
3268
3269

3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293

3294
3295
3296
3297
3298
3299
3300
....
3743
3744
3745
3746
3747
3748
3749
3750

3751
3752
3753
3754
3755
3756
3757
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * ----------------------------------------------------------------------------
 */

#include "tclThreadInt.h"


/*
 * Provide package version in build contexts which do not provide
 * -DPACKAGE_VERSION, like building a shell with the Thread object
 * files built as part of that shell. Example: basekits.
 */
#ifndef PACKAGE_VERSION
................................................................................
/*
 * Structure holding result of the command executed in target thread.
 */

typedef struct ThreadEventResult {
    Tcl_Condition done;                   /* Set when the script completes */
    int code;                             /* Return value of the function */
    char *result;                         /* Result from the function */
    char *errorInfo;                      /* Copy of errorInfo variable */
    char *errorCode;                      /* Copy of errorCode variable */
    Tcl_ThreadId srcThreadId;             /* Id of sender, if it dies */
    Tcl_ThreadId dstThreadId;             /* Id of target, if it dies */
    struct ThreadEvent *eventPtr;         /* Back pointer */
    struct ThreadEventResult *nextPtr;    /* List for cleanup */
    struct ThreadEventResult *prevPtr;
................................................................................
} ThreadEvent;

typedef int  (ThreadSendProc) (Tcl_Interp*, ClientData);
typedef void (ThreadSendFree) (ClientData);

static ThreadSendProc ThreadSendEval;     /* Does a regular Tcl_Eval */
static ThreadSendProc ThreadClbkSetVar;   /* Sets the named variable */


/*
 * These structures are used to communicate commands between source and target
 * threads. The ThreadSendData is used for source->target command passing,
 * while the ThreadClbkData is used for doing asynchronous callbacks.
 *
 * Important: structures below must have first three elements identical!
................................................................................
 */

static void
threadSendFree(ClientData ptr)
{
    ckfree((char *)ptr);
}







static int
ThreadSendObjCmd(dummy, interp, objc, objv)
    ClientData  dummy;          /* Not used. */
    Tcl_Interp *interp;         /* Current interpreter. */
    int         objc;           /* Number of arguments. */
    Tcl_Obj    *const objv[];   /* Argument objects. */
{
    size_t size;
    int ret, ii = 0, flags = 0;
    Tcl_ThreadId thrId;
    const char *script, *arg;
    Tcl_Obj *var = NULL;

    ThreadClbkData *clbkPtr = NULL;
    ThreadSendData *sendPtr = NULL;

................................................................................

    for (ii = 1; ii < objc; ii++) {
        arg = Tcl_GetString(objv[ii]);
        if (OPT_CMP(arg, "-async")) {
            flags &= ~THREAD_SEND_WAIT;
        } else if (OPT_CMP(arg, "-head")) {
            flags |= THREAD_SEND_HEAD;



        } else {
            break;
        }
    }
    if (ii >= objc) {
        goto usage;
    }
................................................................................

    script = Tcl_GetString(objv[ii]);
    size = objv[ii]->length+1;
    if (++ii < objc) {
        var = objv[ii];
    }
    if (var && (flags & THREAD_SEND_WAIT) == 0) {
        const char *varName = Tcl_GetString(var);
        size_t vsize = var->length + 1;

        if (thrId == Tcl_GetCurrentThread()) {
            /*
             * FIXME: Do something for callbacks to self
             */
            Tcl_SetObjResult(interp, Tcl_NewStringObj("can't notify self", -1));
            return TCL_ERROR;
................................................................................
        /*
         * Prepare record for the callback. This is asynchronously
         * posted back to us when the target thread finishes processing.
         * We should do a vwait on the "var" to get notified.
         */

        clbkPtr = (ThreadClbkData*)ckalloc(sizeof(ThreadClbkData));



        clbkPtr->execProc   = ThreadClbkSetVar;

        clbkPtr->freeProc   = threadSendFree;
        clbkPtr->interp     = interp;
        clbkPtr->threadId   = Tcl_GetCurrentThread();
        clbkPtr->clientData = (ClientData)memcpy(ckalloc(vsize), varName, vsize);

    }

    /*
     * Prepare job record for the target thread
     */

    sendPtr = (ThreadSendData*)ckalloc(sizeof(ThreadSendData));
................................................................................

static int
ThreadClbkSetVar(interp, clientData)
    Tcl_Interp *interp;
    ClientData clientData;
{
    ThreadClbkData *clbkPtr = (ThreadClbkData*)clientData;
    const char *var = (const char *)clbkPtr->clientData;
    Tcl_Obj *valObj;
    ThreadEventResult *resultPtr = &clbkPtr->result;
    int rc = TCL_OK;

    /*
     * Get the result of the posted command.
     * We will use it to fill-in the result variable.
     */

    valObj = Tcl_NewStringObj(resultPtr->result, -1);
    Tcl_IncrRefCount(valObj);

    if (resultPtr->result != threadEmptyResult) {
        ckfree(resultPtr->result);
    }

    /*
     * Set the result variable
     */

    if (Tcl_SetVar2Ex(interp, var, NULL, valObj,
                      TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
        rc = TCL_ERROR;
        goto cleanup;
    }

    /*
     * In case of error, trigger the bgerror mechansim
     */

    if (resultPtr->code == TCL_ERROR) {
        if (resultPtr->errorCode) {
            var = "errorCode";
            Tcl_SetVar2Ex(interp, var, NULL, Tcl_NewStringObj(resultPtr->errorCode, -1), TCL_GLOBAL_ONLY);
            ckfree((char*)resultPtr->errorCode);
        }
        if (resultPtr->errorInfo) {
            var = "errorInfo";
            Tcl_SetVar2Ex(interp, var, NULL, Tcl_NewStringObj(resultPtr->errorInfo, -1), TCL_GLOBAL_ONLY);
            ckfree((char*)resultPtr->errorInfo);
        }
        Tcl_SetObjResult(interp, valObj);
        Tcl_BackgroundError(interp);

    }


cleanup:
    Tcl_DecrRefCount(valObj);
    return rc;
}
























 
/*
 *----------------------------------------------------------------------
 *
 * ThreadCreate --
 *
 *  This procedure is invoked to create a thread containing an
................................................................................
        if (resultPtr->errorInfo) {
            Tcl_AddErrorInfo(interp, resultPtr->errorInfo);
            ckfree(resultPtr->errorInfo);
        }
    }

    code = resultPtr->code;
    Tcl_SetObjResult(interp, Tcl_NewStringObj(resultPtr->result, -1));

    /*
     * Cleanup
     */

    Tcl_ConditionFinalize(&resultPtr->done);
    if (resultPtr->result != threadEmptyResult) {
        ckfree(resultPtr->result);
    }
    ckfree((char*)resultPtr);

    return code;
}
 
/*
 *----------------------------------------------------------------------
................................................................................

            if (dowait) {
                while (resultPtr->result == NULL) {
                    Tcl_ConditionWait(&resultPtr->done, &threadMutex, NULL);
                }
                SpliceOut(resultPtr, resultList);
                Tcl_ConditionFinalize(&resultPtr->done);
                if (resultPtr->result != threadEmptyResult) {
                    ckfree(resultPtr->result); /* Will be ignored anyway */
                }
                ckfree((char*)resultPtr);
            }
        }
    }

    Tcl_MutexUnlock(&threadMutex);
    Tcl_SetIntObj(Tcl_GetObjResult(interp), (users > 0) ? users : 0);
................................................................................

static void
ThreadSetResult(interp, code, resultPtr)
    Tcl_Interp *interp;
    int code;
    ThreadEventResult *resultPtr;
{

    size_t size;
    const char *errorCode, *errorInfo, *result;

    if (interp == NULL) {
        code      = TCL_ERROR;
        errorInfo = "";
        errorCode = "THREAD";
        result    = "no target interp!";
        size    = strlen(result);
        resultPtr->result = (size) ?
            memcpy(ckalloc(1+size), result, 1+size) : threadEmptyResult;
    } else {
        result = Tcl_GetString(Tcl_GetObjResult(interp));
        size = Tcl_GetObjResult(interp)->length;
        resultPtr->result = (size) ?
            memcpy(ckalloc(1+size), result, 1+size) : threadEmptyResult;
        if (code == TCL_ERROR) {
            errorCode = Tcl_GetVar2(interp, "errorCode", NULL, TCL_GLOBAL_ONLY);
            errorInfo = Tcl_GetVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY);
        } else {
            errorCode = NULL;
            errorInfo = NULL;
        }
    }


    resultPtr->code = code;

    if (errorCode != NULL) {
        size = strlen(errorCode) + 1;
        resultPtr->errorCode = memcpy(ckalloc(size), errorCode, size);
    } else {
................................................................................

            /*
             * Dang. The target is going away. Unblock the caller.
             * The result string must be dynamically allocated
             * because the main thread is going to call free on it.
             */

            resultPtr->result = strcpy(ckalloc(1+strlen(diemsg)), diemsg);

            resultPtr->code = TCL_ERROR;
            resultPtr->errorCode = resultPtr->errorInfo = NULL;
            Tcl_ConditionNotify(&resultPtr->done);
        }
    }
    for (tResultPtr = transferList; tResultPtr; tResultPtr = tNextPtr) {
        tNextPtr = tResultPtr->nextPtr;







>







 







|







 







>







 







>
>
>
>
>
>









|







 







>
>
>







 







<
<







 







>
>
>
|
>
|


|
>







 







|









<
<
<
<
|
<





|











|
|



|
|




>

>





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







 







|






<
|
<







 







|
<
<







 







>

<





<
<
|
<

|
<
<
<








>







 







|
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
...
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
...
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
...
998
999
1000
1001
1002
1003
1004


1005
1006
1007
1008
1009
1010
1011
....
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
....
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676




1677

1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
....
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866

2867

2868
2869
2870
2871
2872
2873
2874
....
3098
3099
3100
3101
3102
3103
3104
3105


3106
3107
3108
3109
3110
3111
3112
....
3294
3295
3296
3297
3298
3299
3300
3301
3302

3303
3304
3305
3306
3307


3308

3309
3310



3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
....
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * ----------------------------------------------------------------------------
 */

#include "tclThreadInt.h"
#include "threadSvCmd.h"

/*
 * Provide package version in build contexts which do not provide
 * -DPACKAGE_VERSION, like building a shell with the Thread object
 * files built as part of that shell. Example: basekits.
 */
#ifndef PACKAGE_VERSION
................................................................................
/*
 * Structure holding result of the command executed in target thread.
 */

typedef struct ThreadEventResult {
    Tcl_Condition done;                   /* Set when the script completes */
    int code;                             /* Return value of the function */
    Tcl_Obj *result;                      /* Result from the function */
    char *errorInfo;                      /* Copy of errorInfo variable */
    char *errorCode;                      /* Copy of errorCode variable */
    Tcl_ThreadId srcThreadId;             /* Id of sender, if it dies */
    Tcl_ThreadId dstThreadId;             /* Id of target, if it dies */
    struct ThreadEvent *eventPtr;         /* Back pointer */
    struct ThreadEventResult *nextPtr;    /* List for cleanup */
    struct ThreadEventResult *prevPtr;
................................................................................
} ThreadEvent;

typedef int  (ThreadSendProc) (Tcl_Interp*, ClientData);
typedef void (ThreadSendFree) (ClientData);

static ThreadSendProc ThreadSendEval;     /* Does a regular Tcl_Eval */
static ThreadSendProc ThreadClbkSetVar;   /* Sets the named variable */
static ThreadSendProc ThreadClbkCommand;   /* Sets the named variable */

/*
 * These structures are used to communicate commands between source and target
 * threads. The ThreadSendData is used for source->target command passing,
 * while the ThreadClbkData is used for doing asynchronous callbacks.
 *
 * Important: structures below must have first three elements identical!
................................................................................
 */

static void
threadSendFree(ClientData ptr)
{
    ckfree((char *)ptr);
}
 
static void
threadSendObjFree(ClientData ptr)
{
    Tcl_DecrRefCount((Tcl_Obj *)ptr);
}

static int
ThreadSendObjCmd(dummy, interp, objc, objv)
    ClientData  dummy;          /* Not used. */
    Tcl_Interp *interp;         /* Current interpreter. */
    int         objc;           /* Number of arguments. */
    Tcl_Obj    *const objv[];   /* Argument objects. */
{
    size_t size;
    int cmd = 0, ret, ii = 0, flags = 0;
    Tcl_ThreadId thrId;
    const char *script, *arg;
    Tcl_Obj *var = NULL;

    ThreadClbkData *clbkPtr = NULL;
    ThreadSendData *sendPtr = NULL;

................................................................................

    for (ii = 1; ii < objc; ii++) {
        arg = Tcl_GetString(objv[ii]);
        if (OPT_CMP(arg, "-async")) {
            flags &= ~THREAD_SEND_WAIT;
        } else if (OPT_CMP(arg, "-head")) {
            flags |= THREAD_SEND_HEAD;
        } else if (OPT_CMP(arg, "-command")) {
            flags &= ~THREAD_SEND_WAIT;
            cmd = 1;
        } else {
            break;
        }
    }
    if (ii >= objc) {
        goto usage;
    }
................................................................................

    script = Tcl_GetString(objv[ii]);
    size = objv[ii]->length+1;
    if (++ii < objc) {
        var = objv[ii];
    }
    if (var && (flags & THREAD_SEND_WAIT) == 0) {



        if (thrId == Tcl_GetCurrentThread()) {
            /*
             * FIXME: Do something for callbacks to self
             */
            Tcl_SetObjResult(interp, Tcl_NewStringObj("can't notify self", -1));
            return TCL_ERROR;
................................................................................
        /*
         * Prepare record for the callback. This is asynchronously
         * posted back to us when the target thread finishes processing.
         * We should do a vwait on the "var" to get notified.
         */

        clbkPtr = (ThreadClbkData*)ckalloc(sizeof(ThreadClbkData));
        if (cmd) {
            clbkPtr->execProc   = ThreadClbkCommand;
        } else {
            clbkPtr->execProc   = ThreadClbkSetVar;
        }
        clbkPtr->freeProc   = threadSendObjFree;
        clbkPtr->interp     = interp;
        clbkPtr->threadId   = Tcl_GetCurrentThread();
        clbkPtr->clientData = Sv_DuplicateObj(var);
        Tcl_IncrRefCount((Tcl_Obj *)clbkPtr->clientData);
    }

    /*
     * Prepare job record for the target thread
     */

    sendPtr = (ThreadSendData*)ckalloc(sizeof(ThreadSendData));
................................................................................

static int
ThreadClbkSetVar(interp, clientData)
    Tcl_Interp *interp;
    ClientData clientData;
{
    ThreadClbkData *clbkPtr = (ThreadClbkData*)clientData;
    Tcl_Obj *var = (Tcl_Obj *)clbkPtr->clientData;
    Tcl_Obj *valObj;
    ThreadEventResult *resultPtr = &clbkPtr->result;
    int rc = TCL_OK;

    /*
     * Get the result of the posted command.
     * We will use it to fill-in the result variable.
     */





    valObj = resultPtr->result;


    /*
     * Set the result variable
     */

    if (Tcl_ObjSetVar2(interp, var, NULL, valObj,
                      TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
        rc = TCL_ERROR;
        goto cleanup;
    }

    /*
     * In case of error, trigger the bgerror mechansim
     */

    if (resultPtr->code == TCL_ERROR) {
        if (resultPtr->errorCode) {
            Tcl_SetVar2Ex(interp, "errorCode", NULL,
                Tcl_NewStringObj(resultPtr->errorCode, -1), TCL_GLOBAL_ONLY);
            ckfree((char*)resultPtr->errorCode);
        }
        if (resultPtr->errorInfo) {
            Tcl_SetVar2Ex(interp, "errorInfo", NULL,
                Tcl_NewStringObj(resultPtr->errorInfo, -1), TCL_GLOBAL_ONLY);
            ckfree((char*)resultPtr->errorInfo);
        }
        Tcl_SetObjResult(interp, valObj);
        Tcl_BackgroundError(interp);
        return TCL_ERROR;
    }
    return TCL_OK;

cleanup:
    Tcl_DecrRefCount(valObj);
    return rc;
}
 
static int ThreadClbkCommand(Tcl_Interp *interp, ClientData clientData)
{
    int status = TCL_OK;
    ThreadClbkData *clbkPtr = (ThreadClbkData*)clientData;
    Tcl_Obj *script = (Tcl_Obj *)clbkPtr->clientData;
    ThreadEventResult *resultPtr = &clbkPtr->result;

    if (resultPtr->code == TCL_ERROR) {
        Tcl_SetObjResult(interp, resultPtr->result);
        Tcl_BackgroundError(interp);
        goto cleanup;
    }

    if ((status = Tcl_ListObjAppendElement(
        interp, script, resultPtr->result)) != TCL_OK) {
        goto cleanup;
    }
    status = Tcl_GlobalEvalObj(interp, script);

cleanup:
    Tcl_DecrRefCount(resultPtr->result);
    return status;
}
 
/*
 *----------------------------------------------------------------------
 *
 * ThreadCreate --
 *
 *  This procedure is invoked to create a thread containing an
................................................................................
        if (resultPtr->errorInfo) {
            Tcl_AddErrorInfo(interp, resultPtr->errorInfo);
            ckfree(resultPtr->errorInfo);
        }
    }

    code = resultPtr->code;
    Tcl_SetObjResult(interp, resultPtr->result);

    /*
     * Cleanup
     */

    Tcl_ConditionFinalize(&resultPtr->done);

    Tcl_DecrRefCount(resultPtr->result);

    ckfree((char*)resultPtr);

    return code;
}
 
/*
 *----------------------------------------------------------------------
................................................................................

            if (dowait) {
                while (resultPtr->result == NULL) {
                    Tcl_ConditionWait(&resultPtr->done, &threadMutex, NULL);
                }
                SpliceOut(resultPtr, resultList);
                Tcl_ConditionFinalize(&resultPtr->done);
                Tcl_DecrRefCount(resultPtr->result);


                ckfree((char*)resultPtr);
            }
        }
    }

    Tcl_MutexUnlock(&threadMutex);
    Tcl_SetIntObj(Tcl_GetObjResult(interp), (users > 0) ? users : 0);
................................................................................

static void
ThreadSetResult(interp, code, resultPtr)
    Tcl_Interp *interp;
    int code;
    ThreadEventResult *resultPtr;
{
    const char *errorCode, *errorInfo;
    size_t size;


    if (interp == NULL) {
        code      = TCL_ERROR;
        errorInfo = "";
        errorCode = "THREAD";


        resultPtr->result = Tcl_NewStringObj("no target interp", -1);

    } else {
        resultPtr->result = Sv_DuplicateObj(Tcl_GetObjResult(interp));



        if (code == TCL_ERROR) {
            errorCode = Tcl_GetVar2(interp, "errorCode", NULL, TCL_GLOBAL_ONLY);
            errorInfo = Tcl_GetVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY);
        } else {
            errorCode = NULL;
            errorInfo = NULL;
        }
    }
    Tcl_IncrRefCount(resultPtr->result);

    resultPtr->code = code;

    if (errorCode != NULL) {
        size = strlen(errorCode) + 1;
        resultPtr->errorCode = memcpy(ckalloc(size), errorCode, size);
    } else {
................................................................................

            /*
             * Dang. The target is going away. Unblock the caller.
             * The result string must be dynamically allocated
             * because the main thread is going to call free on it.
             */

            resultPtr->result = Tcl_NewStringObj(diemsg, -1);
            Tcl_IncrRefCount(resultPtr->result);
            resultPtr->code = TCL_ERROR;
            resultPtr->errorCode = resultPtr->errorInfo = NULL;
            Tcl_ConditionNotify(&resultPtr->done);
        }
    }
    for (tResultPtr = transferList; tResultPtr; tResultPtr = tNextPtr) {
        tNextPtr = tResultPtr->nextPtr;

Changes to tests/thread.test.

1192
1193
1194
1195
1196
1197
1198















1199
1200
1201
    thread::cond notify $cond
    after 1000
    set c2 [catch {thread::cond destroy $cond} r2]
    ThreadReap
    thread::mutex destroy $emutex
    list $c1 $c2 $r1 $r2
} {1 0 {condition variable is in use} {}}
















removeFile dummyForTransfer
::tcltest::cleanupTests







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



1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
    thread::cond notify $cond
    after 1000
    set c2 [catch {thread::cond destroy $cond} r2]
    ThreadReap
    thread::mutex destroy $emutex
    list $c1 $c2 $r1 $r2
} {1 0 {condition variable is in use} {}}

test thread-22.1  {thread::send -command} {
    ThreadReap
    after 0 [list ::apply [list {} {
        set tid [thread::create]
        thread::send -command $tid {lindex hello} [list ::apply [list args {
            variable result
            set result $args
        } [namespace current]]]
    } [namespace current]]]
    vwait [namespace current]::result
    ThreadReap
    set result
} hello 


removeFile dummyForTransfer
::tcltest::cleanupTests