summaryrefslogtreecommitdiff
path: root/extra/tk/tk-xcircuit.patch
blob: 1fe329e339ce80849c1f3c2518330c096b873c25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
Index: generic/tkConfig.c
==================================================================
--- generic/tkConfig.c
+++ generic/tkConfig.c
@@ -29,11 +29,16 @@
 /*
  * The following definition is an AssocData key used to keep track of all of
  * the option tables that have been created for an interpreter.
  */
 
-#define OPTION_HASH_KEY "TkOptionTable"
+typedef struct ThreadSpecificData {
+    int initialized;		/* 0 means table below needs initializing. */
+    Tcl_HashTable hashTable;
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+
 
 /*
  * The following two structures are used along with Tk_OptionSpec structures
  * to manage configuration options. Tk_OptionSpec is static templates that are
  * compiled into the code of a widget or other object manager. However, to
@@ -98,12 +103,10 @@
 				 * templates, this points to the table
 				 * corresponding to the next template in the
 				 * chain. */
     int numOptions;		/* The number of items in the options array
 				 * below. */
-    int refCount2; /* Reference counter for controlling the freeing
-                    * of the memory occupied by this OptionTable */
     Option options[1];		/* Information about the individual options in
 				 * the table. This must be the last field in
 				 * the structure: the actual size of the array
 				 * will be numOptions, not 1. */
 } OptionTable;
@@ -113,12 +116,10 @@
  */
 
 static int		DoObjConfig(Tcl_Interp *interp, char *recordPtr,
 			    Option *optionPtr, Tcl_Obj *valuePtr,
 			    Tk_Window tkwin, Tk_SavedOption *savePtr);
-static void		DestroyOptionHashTable(ClientData clientData,
-			    Tcl_Interp *interp);
 static void		FreeResources(Option *optionPtr, Tcl_Obj *objPtr,
 			    char *internalPtr, Tk_Window tkwin);
 static Tcl_Obj *	GetConfigList(char *recordPtr,
 			    Option *optionPtr, Tk_Window tkwin);
 static Tcl_Obj *	GetObjectForOption(char *recordPtr,
@@ -168,42 +169,38 @@
 				 * in which this table will be used. */
     const Tk_OptionSpec *templatePtr)
 				/* Static information about the configuration
 				 * options. */
 {
-    Tcl_HashTable *hashTablePtr;
     Tcl_HashEntry *hashEntryPtr;
     int newEntry;
     OptionTable *tablePtr;
     const Tk_OptionSpec *specPtr, *specPtr2;
     Option *optionPtr;
     int numOptions, i;
+    ThreadSpecificData *tsdPtr =
+	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
 
     /*
-     * We use an AssocData value in the interpreter to keep a hash table of
-     * all the option tables we've created for this application. This is used
-     * for two purposes. First, it allows us to share the tables (e.g. in
-     * several chains) and second, we use the deletion callback for the
-     * AssocData to delete all the option tables when the interpreter is
-     * deleted. The code below finds the hash table or creates a new one if it
+     * We use an TSD in the thread to keep a hash table of
+     * all the option tables we've created for this application. This is
+     * used for allowing us to share the tables (e.g. in several chains).
+     * The code below finds the hash table or creates a new one if it
      * doesn't already exist.
      */
 
-    hashTablePtr = Tcl_GetAssocData(interp, OPTION_HASH_KEY, NULL);
-    if (hashTablePtr == NULL) {
-	hashTablePtr = ckalloc(sizeof(Tcl_HashTable));
-	Tcl_InitHashTable(hashTablePtr, TCL_ONE_WORD_KEYS);
-	Tcl_SetAssocData(interp, OPTION_HASH_KEY, DestroyOptionHashTable,
-		hashTablePtr);
+    if (!tsdPtr->initialized) {
+	Tcl_InitHashTable(&tsdPtr->hashTable, TCL_ONE_WORD_KEYS);
+	tsdPtr->initialized = 1;
     }
 
     /*
      * See if a table has already been created for this template. If so, just
      * reuse the existing table.
      */
 
-    hashEntryPtr = Tcl_CreateHashEntry(hashTablePtr, (char *) templatePtr,
+    hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->hashTable, (char *) templatePtr,
 	    &newEntry);
     if (!newEntry) {
 	tablePtr = Tcl_GetHashValue(hashEntryPtr);
 	tablePtr->refCount++;
 	return (Tk_OptionTable) tablePtr;
@@ -218,11 +215,10 @@
     for (specPtr = templatePtr; specPtr->type != TK_OPTION_END; specPtr++) {
 	numOptions++;
     }
     tablePtr = ckalloc(sizeof(OptionTable) + (numOptions * sizeof(Option)));
     tablePtr->refCount = 1;
-    tablePtr->refCount2 = 1;
     tablePtr->hashEntryPtr = hashEntryPtr;
     tablePtr->nextPtr = NULL;
     tablePtr->numOptions = numOptions;
 
     /*
@@ -332,13 +328,20 @@
     Tk_OptionTable optionTable)	/* The option table to delete. */
 {
     OptionTable *tablePtr = (OptionTable *) optionTable;
     Option *optionPtr;
     int count;
+    ThreadSpecificData *tsdPtr =
+	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
 
-    tablePtr->refCount--;
-    if (tablePtr->refCount > 0) {
+    if (tablePtr->refCount > 1) {
+	tablePtr->refCount--;
+	return;
+    }
+
+    if (!tsdPtr->initialized || !Tcl_FindHashEntry(&tsdPtr->hashTable,
+	    tablePtr->hashEntryPtr)) {
 	return;
     }
 
     if (tablePtr->nextPtr != NULL) {
 	Tk_DeleteOptionTable((Tk_OptionTable) tablePtr->nextPtr);
@@ -354,66 +357,11 @@
 		&& (optionPtr->extra.monoColorPtr != NULL)) {
 	    Tcl_DecrRefCount(optionPtr->extra.monoColorPtr);
 	}
     }
     Tcl_DeleteHashEntry(tablePtr->hashEntryPtr);
-    tablePtr->refCount2--;
-    if (tablePtr->refCount2 <= 0) {
-	ckfree(tablePtr);
-    }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DestroyOptionHashTable --
- *
- *	This function is the deletion callback associated with the AssocData
- *	entry created by Tk_CreateOptionTable. It is invoked when an
- *	interpreter is deleted, and deletes all of the option tables
- *	associated with that interpreter.
- *
- * Results:
- *	None.
- *
- * Side effects:
- *	The option hash table is destroyed along with all of the OptionTable
- *	structures that it refers to.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DestroyOptionHashTable(
-    ClientData clientData,	/* The hash table we are destroying */
-    Tcl_Interp *interp)		/* The interpreter we are destroying */
-{
-    Tcl_HashTable *hashTablePtr = clientData;
-    Tcl_HashSearch search;
-    Tcl_HashEntry *hashEntryPtr;
-
-    for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
-	    hashEntryPtr != NULL;
-	    hashEntryPtr = Tcl_NextHashEntry(&search)) {
-	OptionTable *tablePtr = Tcl_GetHashValue(hashEntryPtr);
-
-	/*
-	 * The following statements do two tricky things:
-	 * 1. They ensure that the option table is deleted, even if there are
-	 *    outstanding references to it.
-	 * 2. They ensure that Tk_DeleteOptionTable doesn't delete other
-	 *    tables chained from this one; we'll do it when we come across
-	 *    the hash table entry for the chained table (in fact, the chained
-	 *    table may already have been deleted).
-	 */
-
-	tablePtr->refCount = 1;
-	tablePtr->nextPtr = NULL;
-	Tk_DeleteOptionTable((Tk_OptionTable) tablePtr);
-    }
-    Tcl_DeleteHashTable(hashTablePtr);
-    ckfree(hashTablePtr);
+    ckfree(tablePtr);
 }
 
 /*
  *--------------------------------------------------------------
  *
@@ -1149,11 +1097,11 @@
 	objPtr->typePtr->freeIntRepProc(objPtr);
     }
     objPtr->internalRep.twoPtrValue.ptr1 = (void *) tablePtr;
     objPtr->internalRep.twoPtrValue.ptr2 = (void *) bestPtr;
     objPtr->typePtr = &optionObjType;
-    tablePtr->refCount2++;
+    tablePtr->refCount++;
     return bestPtr;
 
   error:
     if (interp != NULL) {
 	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
@@ -1222,16 +1170,13 @@
 
 static void
 FreeOptionInternalRep(
     register Tcl_Obj *objPtr)	/* Object whose internal rep to free. */
 {
-    register OptionTable *tablePtr = (OptionTable *) objPtr->internalRep.twoPtrValue.ptr1;
+    register Tk_OptionTable tablePtr = (Tk_OptionTable) objPtr->internalRep.twoPtrValue.ptr1;
 
-    tablePtr->refCount2--;
-    if (tablePtr->refCount2 <= 0) {
-	ckfree(tablePtr);
-    }
+    Tk_DeleteOptionTable(tablePtr);
     objPtr->typePtr = NULL;
     objPtr->internalRep.twoPtrValue.ptr1 = NULL;
     objPtr->internalRep.twoPtrValue.ptr2 = NULL;
 }
 
@@ -2111,27 +2056,27 @@
     Tk_OptionTable table)	/* Table about which information is to be
 				 * returned. May not necessarily exist in the
 				 * interpreter anymore. */
 {
     OptionTable *tablePtr = (OptionTable *) table;
-    Tcl_HashTable *hashTablePtr;
     Tcl_HashEntry *hashEntryPtr;
     Tcl_HashSearch search;
     Tcl_Obj *objPtr;
+    ThreadSpecificData *tsdPtr =
+	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
 
     objPtr = Tcl_NewObj();
-    hashTablePtr = Tcl_GetAssocData(interp, OPTION_HASH_KEY, NULL);
-    if (hashTablePtr == NULL) {
+    if (!tablePtr || !tsdPtr->initialized) {
 	return objPtr;
     }
 
     /*
      * Scan all the tables for this interpreter to make sure that the one we
      * want still is valid.
      */
 
-    for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
+    for (hashEntryPtr = Tcl_FirstHashEntry(&tsdPtr->hashTable, &search);
 	    hashEntryPtr != NULL;
 	    hashEntryPtr = Tcl_NextHashEntry(&search)) {
 	if (tablePtr == (OptionTable *) Tcl_GetHashValue(hashEntryPtr)) {
 	    for ( ; tablePtr != NULL; tablePtr = tablePtr->nextPtr) {
 		Tcl_ListObjAppendElement(NULL, objPtr,

Index: generic/tkTest.c
==================================================================
--- generic/tkTest.c
+++ generic/tkTest.c
@@ -801,10 +801,11 @@
 		sizeof(char *), "table", 0, &index) != TCL_OK) {
 	    return TCL_ERROR;
 	}
 	if (tables[index] != NULL) {
 	    Tk_DeleteOptionTable(tables[index]);
+	    tables[index] = NULL;
 	}
 	break;
 
     case INFO:
 	if (objc != 3) {

Index: tests/config.test
==================================================================
--- tests/config.test
+++ tests/config.test
@@ -96,11 +96,11 @@
     testobjconfig chain2 .b
     testobjconfig chain1 .a
     testobjconfig info chain2
 } -cleanup {
     killTables
-} -result {1 4 -three 2 2 -one}
+} -result {2 4 -three 2 2 -one}
 test config-1.8 {Tk_CreateOptionTable - chained tables} -constraints {
     testobjconfig
 } -body {
     testobjconfig chain1 .a
     testobjconfig chain2 .b
@@ -132,11 +132,11 @@
     lappend x [testobjconfig info chain2] [testobjconfig info chain1]
     testobjconfig delete chain2
     lappend x [testobjconfig info chain2] [testobjconfig info chain1]
 } -cleanup {
     killTables
-} -result {{1 4 -three 2 2 -one} {2 2 -one} {} {1 2 -one}}
+} -result {{} {2 2 -one} {} {2 2 -one}}
 
 # No tests for DestroyOptionHashTable; couldn't figure out how to test.
 
 test config-3.1 {Tk_InitOptions - priority of chained tables} -constraints {
     testobjconfig