Tcl package Thread source code

Check-in [9a1fe2aece]
Login
Bounty program for improvements to Tcl and certain Tcl packages.

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

Overview
Comment:Optimize ThreadSendData and ThreadClbkData usage to use only one ckalloc() in stead of two in most situations.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | thread-2-8-branch
Files: files | file ages | folders
SHA3-256: 9a1fe2aece4818ffe7396db37b594136d0c9f298528b1e19e96848f62658f7b7
User & Date: jan.nijtmans 2020-07-16 15:01:28
Context
2020-07-16
15:15
Merge-mark (optimization in 2.8 doesn't make much sense here any more) Leaf check-in: 0f983c4b28 user: jan.nijtmans tags: thread-2-branch
15:01
Optimize ThreadSendData and ThreadClbkData usage to use only one ckalloc() in stead of two in most situations. Leaf check-in: 9a1fe2aece user: jan.nijtmans tags: thread-2-8-branch
14:02
Eliminate internal function threadSendFree(), since it's just the same as ckfree check-in: 248da51b62 user: jan.nijtmans tags: thread-2-8-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/threadCmd.c.

216
217
218
219
220
221
222

223
224
225
226
227
228
229
230
231

232
233
234
235
236
237
238
...
994
995
996
997
998
999
1000
1001
1002
1003
1004

1005
1006
1007
1008
1009
1010
1011
1012
1013
1014

1015
1016
1017
1018
1019
1020
1021
1022
....
1109
1110
1111
1112
1113
1114
1115
1116
1117

1118
1119
1120
1121
1122
1123
1124
1125
....
1618
1619
1620
1621
1622
1623
1624
1625
1626

1627
1628
1629
1630
1631
1632
1633
....
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
 */

typedef struct ThreadSendData {
    ThreadSendProc *execProc;             /* Func to exec in remote thread */
    ClientData clientData;                /* Ptr to pass to send function */
    /* ---- */
    Tcl_Interp *interp;                   /* Interp to run the command */

} ThreadSendData;

typedef struct ThreadClbkData {
    ThreadSendProc *execProc;             /* The callback function */
    ClientData clientData;                /* Ptr to pass to clbk function */
    /* ---- */
    Tcl_Interp *interp;                   /* Interp to run the command */
    Tcl_ThreadId threadId;                /* Thread where to post callback */
    ThreadEventResult result;             /* Returns result asynchronously */

} ThreadClbkData;

/*
 * Event used to transfer a channel between threads.
 */
typedef struct TransferEvent {
    Tcl_Event event;                      /* Must be first */
................................................................................

        /*
         * 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->interp     = interp;
        clbkPtr->threadId   = Tcl_GetCurrentThread();

        clbkPtr->clientData = memcpy(ckalloc(vsize), varName, vsize);
    }

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

    sendPtr = (ThreadSendData*)ckalloc(sizeof(ThreadSendData));
    sendPtr->interp     = NULL; /* Signal to use thread main interp */
    sendPtr->execProc   = ThreadSendEval;

    sendPtr->clientData = memcpy(ckalloc(size), script, size);

    ret = ThreadSend(interp, thrId, sendPtr, clbkPtr, flags);

    if (var && (flags & THREAD_SEND_WAIT)) {

        /*
         * Leave job's result in passed variable
................................................................................
     * to the head of the event queue (as out-of-band message).
     */

    for (ii = 0; ii < nthreads; ii++) {
        if (thrIdArray[ii] == Tcl_GetCurrentThread()) {
            continue; /* Do not broadcast self */
        }
        sendPtr  = (ThreadSendData*)ckalloc(sizeof(ThreadSendData));
        *sendPtr = job;

        sendPtr->clientData = memcpy(ckalloc(size), script, size);
        ThreadSend(interp, thrIdArray[ii], sendPtr, NULL, THREAD_SEND_HEAD);
    }

    ckfree((char*)thrIdArray);
    Tcl_ResetResult(interp);

    return TCL_OK;
................................................................................

static int
ThreadSendEval(
    Tcl_Interp *interp,
    ClientData clientData
) {
    ThreadSendData *sendPtr = (ThreadSendData*)clientData;
    char *script = (char*)sendPtr->clientData;


    return Tcl_EvalEx(interp, script, -1, TCL_EVAL_GLOBAL);
}
 
/*
 *----------------------------------------------------------------------
 *
 * ThreadClbkSetVar --
................................................................................

static int
ThreadClbkSetVar(
    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.







>









>







 







|



>
|






|


>
|







 







|

>
|







 







|

>







 







|







216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
...
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
....
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
....
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
....
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
 */

typedef struct ThreadSendData {
    ThreadSendProc *execProc;             /* Func to exec in remote thread */
    ClientData clientData;                /* Ptr to pass to send function */
    /* ---- */
    Tcl_Interp *interp;                   /* Interp to run the command */
    char script[1];                       /* Script to be executed */
} ThreadSendData;

typedef struct ThreadClbkData {
    ThreadSendProc *execProc;             /* The callback function */
    ClientData clientData;                /* Ptr to pass to clbk function */
    /* ---- */
    Tcl_Interp *interp;                   /* Interp to run the command */
    Tcl_ThreadId threadId;                /* Thread where to post callback */
    ThreadEventResult result;             /* Returns result asynchronously */
    char var[1];                          /* Variable name to be set */
} ThreadClbkData;

/*
 * Event used to transfer a channel between threads.
 */
typedef struct TransferEvent {
    Tcl_Event event;                      /* Must be first */
................................................................................

        /*
         * 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) + vsize);
        clbkPtr->execProc   = ThreadClbkSetVar;
        clbkPtr->interp     = interp;
        clbkPtr->threadId   = Tcl_GetCurrentThread();
        memcpy(clbkPtr->var, varName, vsize);
        clbkPtr->clientData = NULL;
    }

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

    sendPtr = (ThreadSendData*)ckalloc(sizeof(ThreadSendData) + size);
    sendPtr->interp     = NULL; /* Signal to use thread main interp */
    sendPtr->execProc   = ThreadSendEval;
    memcpy(sendPtr->script, script, size);
    sendPtr->clientData = NULL;

    ret = ThreadSend(interp, thrId, sendPtr, clbkPtr, flags);

    if (var && (flags & THREAD_SEND_WAIT)) {

        /*
         * Leave job's result in passed variable
................................................................................
     * to the head of the event queue (as out-of-band message).
     */

    for (ii = 0; ii < nthreads; ii++) {
        if (thrIdArray[ii] == Tcl_GetCurrentThread()) {
            continue; /* Do not broadcast self */
        }
        sendPtr  = (ThreadSendData*)ckalloc(sizeof(ThreadSendData) + size);
        *sendPtr = job;
        memcpy(sendPtr->script, script, size);
        sendPtr->clientData = NULL;
        ThreadSend(interp, thrIdArray[ii], sendPtr, NULL, THREAD_SEND_HEAD);
    }

    ckfree((char*)thrIdArray);
    Tcl_ResetResult(interp);

    return TCL_OK;
................................................................................

static int
ThreadSendEval(
    Tcl_Interp *interp,
    ClientData clientData
) {
    ThreadSendData *sendPtr = (ThreadSendData*)clientData;
    char *script = (char *)sendPtr->clientData;

    if (!script) script = sendPtr->script;
    return Tcl_EvalEx(interp, script, -1, TCL_EVAL_GLOBAL);
}
 
/*
 *----------------------------------------------------------------------
 *
 * ThreadClbkSetVar --
................................................................................

static int
ThreadClbkSetVar(
    Tcl_Interp *interp,
    ClientData clientData
) {
    ThreadClbkData *clbkPtr = (ThreadClbkData*)clientData;
    const char *var = clbkPtr->var;
    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.