summaryrefslogtreecommitdiffstats
path: root/unix/dltest
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2021-05-18 12:02:55 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2021-05-18 12:02:55 (GMT)
commit39ef112133e88eb09bd7a2a6cdcf970659d5db09 (patch)
tree3a28dc4b1c7193ffe610d6b06d04a5295534314d /unix/dltest
parent05b875c56459e7ab5f42d3285e7342abc8b0e996 (diff)
downloadtcl-39ef112133e88eb09bd7a2a6cdcf970659d5db09.zip
tcl-39ef112133e88eb09bd7a2a6cdcf970659d5db09.tar.gz
tcl-39ef112133e88eb09bd7a2a6cdcf970659d5db09.tar.bz2
Make Pkgua package thread-safe and properly clean up everything when being unloaded. Based on pyk-tclUnload branch, but extended for thread-safety (Thanks!)
Diffstat (limited to 'unix/dltest')
-rw-r--r--unix/dltest/pkgua.c53
1 files changed, 33 insertions, 20 deletions
diff --git a/unix/dltest/pkgua.c b/unix/dltest/pkgua.c
index 9dde4fa..07556d1 100644
--- a/unix/dltest/pkgua.c
+++ b/unix/dltest/pkgua.c
@@ -22,6 +22,7 @@ static int PkguaEqObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
static int PkguaQuoteObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
+static void CommandDeleted(ClientData clientData);
/*
* In the following hash table we are going to store a struct that holds all
@@ -31,23 +32,32 @@ static int PkguaQuoteObjCmd(ClientData clientData,
* need to keep the various command tokens we have registered, as they are the
* only safe way to unregister our registered commands, even if they have been
* renamed.
- *
- * Note that this code is utterly single-threaded.
*/
-static Tcl_HashTable interpTokenMap;
-static int interpTokenMapInitialised = 0;
+typedef struct ThreadSpecificData {
+ int interpTokenMapInitialised;
+ Tcl_HashTable interpTokenMap;
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
#define MAX_REGISTERED_COMMANDS 2
+static void
+CommandDeleted(ClientData clientData)
+{
+ Tcl_Command *cmdToken = (Tcl_Command *)clientData;
+ *cmdToken = NULL;
+}
static void
PkguaInitTokensHashTable(void)
{
- if (interpTokenMapInitialised) {
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
+
+ if (tsdPtr->interpTokenMapInitialised) {
return;
}
- Tcl_InitHashTable(&interpTokenMap, TCL_ONE_WORD_KEYS);
- interpTokenMapInitialised = 1;
+ Tcl_InitHashTable(&tsdPtr->interpTokenMap, TCL_ONE_WORD_KEYS);
+ tsdPtr->interpTokenMapInitialised = 1;
}
static void
@@ -55,12 +65,13 @@ PkguaFreeTokensHashTable(void)
{
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
- for (entryPtr = Tcl_FirstHashEntry(&interpTokenMap, &search);
+ for (entryPtr = Tcl_FirstHashEntry(&tsdPtr->interpTokenMap, &search);
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
}
- interpTokenMapInitialised = 0;
+ tsdPtr->interpTokenMapInitialised = 0;
}
static Tcl_Command *
@@ -69,13 +80,14 @@ PkguaInterpToTokens(
{
int newEntry;
Tcl_Command *cmdTokens;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
Tcl_HashEntry *entryPtr =
- Tcl_CreateHashEntry(&interpTokenMap, (char *) interp, &newEntry);
+ Tcl_CreateHashEntry(&tsdPtr->interpTokenMap, (char *) interp, &newEntry);
if (newEntry) {
cmdTokens = (Tcl_Command *)
- Tcl_Alloc(sizeof(Tcl_Command) * (MAX_REGISTERED_COMMANDS+1));
- for (newEntry=0 ; newEntry<MAX_REGISTERED_COMMANDS+1 ; ++newEntry) {
+ Tcl_Alloc(sizeof(Tcl_Command) * (MAX_REGISTERED_COMMANDS));
+ for (newEntry=0 ; newEntry<MAX_REGISTERED_COMMANDS ; ++newEntry) {
cmdTokens[newEntry] = NULL;
}
Tcl_SetHashValue(entryPtr, cmdTokens);
@@ -89,8 +101,9 @@ static void
PkguaDeleteTokens(
Tcl_Interp *interp)
{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
Tcl_HashEntry *entryPtr =
- Tcl_FindHashEntry(&interpTokenMap, (char *) interp);
+ Tcl_FindHashEntry(&tsdPtr->interpTokenMap, (char *) interp);
if (entryPtr) {
Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
@@ -200,7 +213,7 @@ Pkgua_Init(
Tcl_Interp *interp) /* Interpreter in which the package is to be
* made available. */
{
- int code, cmdIndex = 0;
+ int code;
Tcl_Command *cmdTokens;
if (Tcl_InitStubs(interp, "8.5", 0) == NULL) {
@@ -208,7 +221,7 @@ Pkgua_Init(
}
/*
- * Initialise our Hash table, where we store the registered command tokens
+ * Initialize our Hash table, where we store the registered command tokens
* for each interpreter.
*/
@@ -222,12 +235,12 @@ Pkgua_Init(
Tcl_SetVar2(interp, "::pkgua_loaded", NULL, ".", TCL_APPEND_VALUE);
cmdTokens = PkguaInterpToTokens(interp);
- cmdTokens[cmdIndex++] =
- Tcl_CreateObjCommand(interp, "pkgua_eq", PkguaEqObjCmd, NULL,
- NULL);
- cmdTokens[cmdIndex++] =
+ cmdTokens[0] =
+ Tcl_CreateObjCommand(interp, "pkgua_eq", PkguaEqObjCmd, &cmdTokens[0],
+ CommandDeleted);
+ cmdTokens[1] =
Tcl_CreateObjCommand(interp, "pkgua_quote", PkguaQuoteObjCmd,
- NULL, NULL);
+ &cmdTokens[1], CommandDeleted);
return TCL_OK;
}