Tcl package Thread source code

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

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

Overview
Comment:Eliminate internal function threadSendFree(), since it's just the same as ckfree
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | thread-2-8-branch
Files: files | file ages | folders
SHA3-256: 248da51b624fb8ea517d5a3f927d4b9baca4b59fc33752a4cf3447418e90069d
User & Date: jan.nijtmans 2020-07-16 14:02:28
Context
2020-07-16
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
2020-07-09
14:28
If internal TclGetIntForIndex stub entry is available in Tcl, always use this one. check-in: 8c20940302 user: jan.nijtmans tags: thread-2-8-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/threadCmd.c.

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
....
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
....
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
....
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
....
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
    struct ThreadSendData *sendData;      /* See below */
    struct ThreadClbkData *clbkData;      /* See below */
    struct ThreadEventResult *resultPtr;  /* To communicate the result back.
                                           * NULL if we don't care about it */
} 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!
 */

typedef struct ThreadSendData {
    ThreadSendProc *execProc;             /* Func to exec in remote thread */
    ClientData clientData;                /* Ptr to pass to send function */
    ThreadSendFree *freeProc;             /* Function to free client data */
     /* ---- */
    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 */
    ThreadSendFree *freeProc;             /* Function to free client data */
    /* ---- */
    Tcl_Interp *interp;                   /* Interp to run the command */
    Tcl_ThreadId threadId;                /* Thread where to post callback */
    ThreadEventResult result;             /* Returns result asynchronously */
} ThreadClbkData;

/*
................................................................................
 *
 * Side effects:
 *  None.
 *
 *----------------------------------------------------------------------
 */

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

static int
ThreadSendObjCmd(
    ClientData  dummy,         /* Not used. */
    Tcl_Interp *interp,        /* Current interpreter. */
    int         objc,          /* Number of arguments. */
    Tcl_Obj    *const objv[]   /* Argument objects. */
) {
................................................................................
         * 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 = 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->freeProc   = threadSendFree;
    sendPtr->clientData = memcpy(ckalloc(size), script, size);

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

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

        /*
................................................................................
    /*
     * Prepare the structure with the job description
     * to be sent asynchronously to each known thread.
     */

    job.interp     = NULL; /* Signal to use thread's main interp */
    job.execProc   = ThreadSendEval;
    job.freeProc   = threadSendFree;
    job.clientData = NULL;

    /*
     * Now, circle this list and send each thread the script.
     * This is sent asynchronously, since we do not care what
     * are they going to do with it. Also, the event is queued
     * to the head of the event queue (as out-of-band message).
................................................................................
        ThreadGetHandle(Tcl_GetCurrentThread(), buf);
        argv[0] = errorProcString;
        argv[1] = buf;
        argv[2] = errorInfo;

        sendPtr = (ThreadSendData*)ckalloc(sizeof(ThreadSendData));
        sendPtr->execProc   = ThreadSendEval;
        sendPtr->freeProc   = threadSendFree;
        sendPtr->clientData = Tcl_Merge(3, argv);
        sendPtr->interp     = NULL;

        ThreadSend(interp, errorThreadId, sendPtr, NULL, 0);
    }
}
 
................................................................................
     * This will free send and/or callback structures
     * since both are the same in the beginning.
     */

    ThreadSendData *anyPtr = (ThreadSendData*)clientData;

    if (anyPtr) {
        if (anyPtr->clientData) {
            (*anyPtr->freeProc)(anyPtr->clientData);
        }
        ckfree((char*)anyPtr);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * ThreadDeleteEvent --







<









|





<
|






<







 







<
<
<
<
<
<







 







<












<







 







<







 







<







 







|
|
|
|







199
200
201
202
203
204
205

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227

228
229
230
231
232
233
234
...
922
923
924
925
926
927
928






929
930
931
932
933
934
935
...
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
....
1096
1097
1098
1099
1100
1101
1102

1103
1104
1105
1106
1107
1108
1109
....
1959
1960
1961
1962
1963
1964
1965

1966
1967
1968
1969
1970
1971
1972
....
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
    struct ThreadSendData *sendData;      /* See below */
    struct ThreadClbkData *clbkData;      /* See below */
    struct ThreadEventResult *resultPtr;  /* To communicate the result back.
                                           * NULL if we don't care about it */
} ThreadEvent;

typedef int  (ThreadSendProc) (Tcl_Interp*, 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 two elements identical!
 */

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;

/*
................................................................................
 *
 * Side effects:
 *  None.
 *
 *----------------------------------------------------------------------
 */







static int
ThreadSendObjCmd(
    ClientData  dummy,         /* Not used. */
    Tcl_Interp *interp,        /* Current interpreter. */
    int         objc,          /* Number of arguments. */
    Tcl_Obj    *const objv[]   /* Argument objects. */
) {
................................................................................
         * 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)) {

        /*
................................................................................
    /*
     * Prepare the structure with the job description
     * to be sent asynchronously to each known thread.
     */

    job.interp     = NULL; /* Signal to use thread's main interp */
    job.execProc   = ThreadSendEval;

    job.clientData = NULL;

    /*
     * Now, circle this list and send each thread the script.
     * This is sent asynchronously, since we do not care what
     * are they going to do with it. Also, the event is queued
     * to the head of the event queue (as out-of-band message).
................................................................................
        ThreadGetHandle(Tcl_GetCurrentThread(), buf);
        argv[0] = errorProcString;
        argv[1] = buf;
        argv[2] = errorInfo;

        sendPtr = (ThreadSendData*)ckalloc(sizeof(ThreadSendData));
        sendPtr->execProc   = ThreadSendEval;

        sendPtr->clientData = Tcl_Merge(3, argv);
        sendPtr->interp     = NULL;

        ThreadSend(interp, errorThreadId, sendPtr, NULL, 0);
    }
}
 
................................................................................
     * This will free send and/or callback structures
     * since both are the same in the beginning.
     */

    ThreadSendData *anyPtr = (ThreadSendData*)clientData;

    if (anyPtr) {
	if (anyPtr->clientData) {
	    ckfree((char *)anyPtr->clientData);
	}
	ckfree((char*)anyPtr);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * ThreadDeleteEvent --