There are no available options for this view.

Parent Directory Parent Directory | Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a> Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a>

Revision 1.7 - (show annotations) (download) (as text)
Fri Jun 20 08:06:32 2008 UTC (9 years, 6 months ago) by gneumann
Branch: MAIN
CVS Tags: aolserver_v45_r2_rc0, HEAD
Branch point for: aolserver_v45_r1, aolserver_v45_r2
Changes since 1.6: +2 -2 lines
File MIME type: text/x-chdr
remove direct access to interp->result, initializing potentially uninitialized variables
1 /*
2 * The contents of this file are subject to the AOLserver Public License
3 * Version 1.1 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://aolserver.com/.
6 *
7 * Software distributed under the License is distributed on an "AS IS"
8 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9 * the License for the specific language governing rights and limitations
10 * under the License.
11 *
12 * The Original Code is AOLserver Code and related documentation
13 * distributed by AOL.
14 *
15 * The Initial Developer of the Original Code is America Online,
16 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
17 * Inc. All Rights Reserved.
18 *
19 * Alternatively, the contents of this file may be used under the terms
20 * of the GNU General Public License (the "GPL"), in which case the
21 * provisions of GPL are applicable instead of those above. If you wish
22 * to allow use of your version of this file only under the terms of the
23 * GPL and not to allow others to use your version of this file under the
24 * License, indicate your decision by deleting the provisions above and
25 * replace them with the notice and other provisions required by the GPL.
26 * If you do not delete the provisions above, a recipient may use your
27 * version of this file under either the License or the GPL.
28 */
29
30 /*
31 * tclshare.c --
32 *
33 * This file implements shared Tcl variables between interpreters.
34 */
35
36 #include "nsd.h"
37
38 /*
39 * Shared variables are implemented with a per-server hash table
40 * that is keyed by the variable name. The table entries store
41 * the shared value and a lock. As some point we may want to
42 * reduce the number of locks by sharing them among variables.
43 */
44
45 typedef struct NsShareVar {
46 Ns_Cs lock; /* Lock to serialize access to the value */
47 int shareCount; /* Number of threads sharing the value */
48 int flags; /* Undefined, scalar, or array */
49 Tcl_Obj *objPtr; /* Value for Scalar values */
50 Tcl_HashTable array; /* Values for Array values */
51 } NsShareVar;
52
53 #define SHARE_UNDEFINED 0x0
54 #define SHARE_SCALAR 0x1
55 #define SHARE_ARRAY 0x2
56 #define SHARE_TRACE 0x8
57
58 /*
59 * Static functions defined in this file.
60 */
61
62 static void <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareUnsetVar">ShareUnsetVar</a>(Tcl_Interp *interp, char *varName,
63 NsShareVar *valuePtr);
64 static Tcl_VarTraceProc <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareTraceProc">ShareTraceProc</a>;
65 static int <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareVar">ShareVar</a>(NsInterp *itPtr, Tcl_Interp *interp, char *varName);
66 static int <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_InitShare">InitShare</a>(NsServer *servPtr, Tcl_Interp *interp,
67 char *varName, char *script);
68 static void <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_RegisterShare">RegisterShare</a>(NsInterp *itPtr, Tcl_Interp *interp,
69 char *varName, NsShareVar *valuePtr);
70 static char *<a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_GetGlobalizedName">GetGlobalizedName</a>(Tcl_DString *dsPtr, char *varName);
71
72
73 /*
74 *----------------------------------------------------------------------
75 *
76 * <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_NsTclShareCmd">NsTclShareCmd</a> --
77 *
78 * This procedure is invoked to process the "ns_share" Tcl command.
79 * It links the variables passed in to values that are shared.
80 *
81 * Results:
82 * A standard Tcl result value.
83 *
84 * Side effects:
85 * Very similar to "global"
86 *
87 *----------------------------------------------------------------------
88 */
89
90 int
91 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_NsTclShareCmd">NsTclShareCmd</a>(ClientData arg, Tcl_Interp *interp, int argc, char **argv)
92 {
93 NsInterp *itPtr = arg;
94
95 if (argc < 2) {
96 Tcl_AppendResult(interp, "wrong # args: should be \"",
97 argv[0], " ?-init script? varName ?varName ...?\"", NULL);
98 return TCL_ERROR;
99 }
100 if (STREQ(argv[1], "-init")) {
101 if (argc != 4) {
102 Tcl_AppendResult(interp, "wrong # args: should be \"",
103 argv[0], " -init script varName\"", NULL);
104 return TCL_ERROR;
105 }
106 if (<a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareVar">ShareVar</a>(itPtr, interp, argv[3]) != TCL_OK ||
107 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_InitShare">InitShare</a>(itPtr->servPtr, interp, argv[3], argv[2]) != TCL_OK) {
108 return TCL_ERROR;
109 }
110 } else {
111 for (argc--, argv++; argc > 0; argc--, argv++) {
112 if (<a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareVar">ShareVar</a>(itPtr, interp, *argv) != TCL_OK) {
113 return TCL_ERROR;
114 }
115 }
116 }
117 return TCL_OK;
118 }
119
120
121 /*
122 *----------------------------------------------------------------------
123 *
124 * <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_InitShare">InitShare</a> --
125 *
126 * Helper routine to initialize a shared variable once, invoke
127 * by a call to ns_share -init.
128 *
129 * Results:
130 * A standard Tcl result value.
131 *
132 * Side effects:
133 * Init script is evaluated once.
134 *
135 *----------------------------------------------------------------------
136 */
137
138 static int
139 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_InitShare">InitShare</a>(NsServer *servPtr, Tcl_Interp *interp, char *varName, char *script)
140 {
141 Tcl_HashEntry *hPtr;
142 int new, result;
143
144 Ns_MutexLock(&servPtr->share.lock);
145 hPtr = Tcl_CreateHashEntry(&servPtr->share.inits, varName, &new);
146 if (!new) {
147 while (Tcl_GetHashValue(hPtr) == NULL) {
148 Ns_CondWait(&servPtr->share.cond, &servPtr->share.lock);
149 }
150 result = TCL_OK;
151 } else {
152 Ns_MutexUnlock(&servPtr->share.lock);
153 result = Tcl_EvalEx(interp, script, -1, 0);
154 Ns_MutexLock(&servPtr->share.lock);
155 Tcl_SetHashValue(hPtr, (ClientData) 1);
156 Ns_CondBroadcast(&servPtr->share.cond);
157 }
158 Ns_MutexUnlock(&servPtr->share.lock);
159 return result;
160 }
161
162
163 /*
164 *----------------------------------------------------------------------
165 *
166 * <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareVar">ShareVar</a> --
167 *
168 * Declare that a variable is shared among interpreters.
169 *
170 * Results:
171 * A standard Tcl result.
172 *
173 * Side effects:
174 * This registers the shared variable in a global hash table
175 * and sets of variable traces to keep the variable in sync.
176 *
177 *----------------------------------------------------------------------
178 */
179
180 static int
181 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareVar">ShareVar</a>(NsInterp *itPtr, Tcl_Interp *interp, char *varName)
182 {
183 NsServer *servPtr = itPtr->servPtr;
184 Tcl_HashEntry *hPtr;
185 Tcl_DString ds;
186 NsShareVar *valuePtr;
187 char *s;
188 char* globalizedVarName;
189 int new;
190
191 /*
192 * Ensure the variable to share is a scalar or whole array.
193 */
194
195 if ((s = strchr(varName, '(')) != NULL && (strchr(s, ')') != NULL)) {
196 Tcl_AppendResult(interp, "can't share ", varName,
197 ": must share whole arrays", (char *) NULL);
198 return TCL_ERROR;
199 }
200
201 /*
202 * Create the shared variable entry if it doesn't already exist.
203 */
204
205 globalizedVarName = <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_GetGlobalizedName">GetGlobalizedName</a>(&ds, varName);
206 Ns_CsEnter(&servPtr->share.cs);
207 hPtr = Tcl_CreateHashEntry(&servPtr->share.vars, globalizedVarName, &new);
208 if (!new) {
209 valuePtr = Tcl_GetHashValue(hPtr);
210 } else {
211 valuePtr = ns_calloc(1, sizeof(NsShareVar));
212 Ns_CsInit(&valuePtr->lock);
213 valuePtr->flags = SHARE_UNDEFINED;
214
215 /*
216 * See if the variable exists already as a global variable
217 * If it does get its current value.
218 */
219
220 if (Tcl_VarEval(interp, "info exists ", globalizedVarName, NULL) != TCL_OK) {
221 Tcl_AppendResult(interp, "error sharing ", globalizedVarName, " can't determine existence of variable", (char *) NULL);
222 Tcl_DStringFree(&ds);
223 return TCL_ERROR;
224 }
225
226 if (strcmp(Tcl_GetStringResult(interp), "1") == 0) {
227 /*
228 * Get existing value in variable being shared.
229 */
230
231 valuePtr->objPtr = Tcl_GetVar2Ex(interp, globalizedVarName, NULL, TCL_LEAVE_ERR_MSG);
232 if (valuePtr->objPtr != NULL) {
233 char *string;
234 int length;
235
236 string = Tcl_GetStringFromObj(valuePtr->objPtr, &length);
237 valuePtr->objPtr = Tcl_NewStringObj(string, length);
238 Tcl_IncrRefCount(valuePtr->objPtr);
239 valuePtr->flags = SHARE_SCALAR;
240 } else {
241 if (Tcl_VarEval(interp, "array get ", globalizedVarName, NULL) == TCL_OK) {
242 /*
243 * Probably an array.
244 */
245 int argc;
246 char **argv;
247 int x;
248 Tcl_InitHashTable(&valuePtr->array, TCL_STRING_KEYS);
249 if (Tcl_SplitList(interp, Tcl_GetStringResult(interp), &argc,
250 (CONST char***)&argv) == TCL_OK) {
251 for (x = 0; x < argc; x += 2) {
252 Tcl_HashEntry* newEntry;
253 Tcl_Obj* newObj;
254 int new;
255 newEntry = Tcl_CreateHashEntry(&valuePtr->array, argv[x], &new);
256 newObj = Tcl_NewStringObj(argv[x + 1], -1);
257 Tcl_IncrRefCount(newObj);
258 Tcl_SetHashValue(newEntry, (ClientData) newObj);
259 }
260 Tcl_Free((char*) argv);
261 }
262 valuePtr->flags = SHARE_ARRAY;
263 }
264 }
265 Tcl_VarEval(interp, "unset ", globalizedVarName, NULL);
266 }
267 Tcl_SetHashValue(hPtr, valuePtr);
268 }
269 valuePtr->shareCount++;
270
271 /*
272 * Register the variable in a per-thread table.
273 * Declare it as a global variable.
274 */
275
276 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_RegisterShare">RegisterShare</a>(itPtr, interp, globalizedVarName, valuePtr);
277 Tcl_VarEval(interp, "global ", varName, NULL);
278
279 Ns_CsLeave(&servPtr->share.cs);
280
281 /*
282 * The value in the shared table is independent of the values
283 * in each thread's shared variable. If a thread deletes its
284 * global variable, the UNSET trace will hook up to the
285 * shared value again. There is no need to put extra
286 * reference counts on the variable to preserver the shared value.
287 */
288
289 Tcl_DStringFree(&ds);
290 return TCL_OK;
291 }
292
293 /*
294 *----------------------------------------------------------------------
295 *
296 * <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_RegisterShare">RegisterShare</a> --
297 *
298 * Set up a trace the first time we see a share variable.
299 *
300 * Results:
301 * None.
302 *
303 * Side effects:
304 * Enter the share name in the per-thread hash table.
305 *
306 *----------------------------------------------------------------------
307 */
308
309 static void
310 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_RegisterShare">RegisterShare</a>(itPtr, interp, varName, valuePtr)
311 NsInterp *itPtr; /* Virtual server. */
312 Tcl_Interp *interp; /* The interpreter */
313 char *varName; /* Share name */
314 NsShareVar *valuePtr; /* Handle on shared value */
315 {
316 int traceFlags = TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_TRACE_READS | TCL_TRACE_ARRAY;
317 ClientData data, shareData;
318
319 /*
320 * Check if there's an existing ns_share trace on the variable.
321 * Tcl_VarTraceInfo will return the clientData for each
322 * trace in reverse order in which they were created. For ns_share
323 * the address of the <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_RegisterShare">RegisterShare</a> function is used as
324 * a reasonably unique value. We look at the data for each
325 * trace until this value is found or NULL which normally
326 * indicates no more traces.
327 */
328
329 shareData = (ClientData) <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_RegisterShare">RegisterShare</a>;
330 data = NULL;
331 do {
332 data = Tcl_VarTraceInfo(interp, varName, traceFlags, <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareTraceProc">ShareTraceProc</a>, data);
333 } while (data != shareData && data != NULL);
334
335 if (data == NULL) {
336
337 /*
338 * There appears to be no existing ns_share trace on the variable.
339 * Note this code could be fooled by some other trace being registered
340 * with NULL clientData. Oh well.
341 */
342
343 if (valuePtr->flags & SHARE_SCALAR) {
344 Tcl_SetVar2Ex(interp, varName, NULL, Tcl_DuplicateObj(valuePtr->objPtr),
345 TCL_GLOBAL_ONLY);
346 } else if (valuePtr->flags & SHARE_ARRAY) {
347 Tcl_HashSearch search;
348 Tcl_HashEntry* hPtr;
349
350 hPtr = Tcl_FirstHashEntry(&valuePtr->array, &search);
351 while (hPtr != NULL) {
352 char* key;
353 Tcl_Obj* objPtr;
354
355 key = Tcl_GetHashKey(&valuePtr->array, hPtr);
356 objPtr = Tcl_GetHashValue(hPtr);
357 Tcl_SetVar2Ex(interp, varName, key,
358 Tcl_DuplicateObj(objPtr), TCL_GLOBAL_ONLY);
359 hPtr = Tcl_NextHashEntry(&search);
360 }
361 }
362 if (Tcl_TraceVar2(interp, varName, (char *) NULL, traceFlags,
363 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareTraceProc">ShareTraceProc</a>, shareData) != TCL_OK) {
364 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Fatal">Ns_Fatal</a>("ns_share: could not trace: %s", varName);
365 }
366 }
367 }
368
369 /*
370 *----------------------------------------------------------------------
371 *
372 * <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareUnsetVar">ShareUnsetVar</a> --
373 *
374 * Carefully unset the variable associated with a shared value.
375 * We must flag the unset as being "our own" so we don't
376 * deadlock in the <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareTraceProc">ShareTraceProc</a>, and we have to restore
377 * the variable tracing.
378 *
379 * Results:
380 * None.
381 *
382 * Side effects:
383 * Tcl_UnsetVar
384 *
385 *----------------------------------------------------------------------
386 */
387
388 static void
389 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareUnsetVar">ShareUnsetVar</a>(interp, varName, valuePtr)
390 Tcl_Interp *interp; /* The interpreter */
391 char *varName; /* Scaler, array, or array element name */
392 NsShareVar *valuePtr; /* Shared variable state, must be locked */
393 {
394 valuePtr->flags |= SHARE_TRACE;
395 Tcl_UnsetVar(interp, varName, 0);
396 if (Tcl_TraceVar2(interp, varName, (char *) NULL,
397 TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
398 TCL_TRACE_READS | TCL_TRACE_ARRAY, <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareTraceProc">ShareTraceProc</a>,
399 (ClientData) NULL) != TCL_OK) {
400 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Fatal">Ns_Fatal</a>("ns_share: could not trace: %s", varName);
401 }
402 valuePtr->flags &= ~SHARE_TRACE;
403 }
404
405
406 /*
407 *----------------------------------------------------------------------
408 *
409 * <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareTraceProc">ShareTraceProc</a> --
410 *
411 * This procedure is invoked whenever a shared variable
412 * is read, modified or deleted. It propagates the change to the
413 * values in the share table.
414 *
415 * Results:
416 * Always returns NULL to indicate success.
417 *
418 * Side effects:
419 * The interpreter variable is kept in sync with the shared value.
420 *
421 *----------------------------------------------------------------------
422 */
423
424 /* ARGSUSED */
425 static char *
426 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareTraceProc">ShareTraceProc</a>(clientData, interp, name1, name2, flags)
427 ClientData clientData; /* Not used. */
428 Tcl_Interp *interp; /* Interpreter whose share variable is
429 * being modified. */
430 CONST char *name1; /* Name of the shared variable. */
431 CONST char *name2; /* Name of variable being modified, or NULL
432 * if whole array is being deleted (UTF-8). */
433 int flags; /* Indicates what's happening. */
434 {
435 NsShareVar *valuePtr; /* The shared value */
436 Tcl_HashEntry *hPtr; /* Current hash table item */
437 Tcl_HashEntry *nextPtr; /* Next hash table item */
438 Tcl_HashSearch search; /* For iterating through shared arrays */
439 Tcl_Obj *objPtr; /* The value in the variable */
440 Tcl_Obj *oldObjPtr; /* The previous shared value */
441 Tcl_Obj *newObjPtr; /* The new shared value */
442 int new; /* For CreateHashEntry */
443 int destroyed = 0; /* True if share value is destroyed */
444 int bail = 0; /* True if this is a recursive trace */
445 char* string; /* String form of shared value */
446 int length; /* Length of string */
447 char *name;
448 Tcl_DString ds; /* Buffer for globalized name */
449 NsInterp *itPtr = <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_NsGetInterpData">NsGetInterpData</a>(interp);
450 NsServer *servPtr = itPtr->servPtr;
451
452 name = (char*)<a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_GetGlobalizedName">GetGlobalizedName</a>(&ds, (char*)name1);
453
454 Ns_CsEnter(&servPtr->share.cs);
455 hPtr = Tcl_FindHashEntry(&servPtr->share.vars, name);
456 if (hPtr == NULL) {
457 /*
458 * This trace is firing on an upvar alias to the shared variable.
459 * Punt because there is no exported Tcl API to get the real
460 * variable name. Also lets us cheat and unset the shared
461 * variable in the interpreter without reflecting the unset
462 * down into the shared value. HACK ALERT.
463 */
464 Ns_CsLeave(&servPtr->share.cs);
465 goto done;
466 }
467 valuePtr = Tcl_GetHashValue(hPtr);
468
469 /*
470 * Shared variables are persistent until the interpreter is destroyed.
471 * When the last interpreter sharing the value goes away, so
472 * does the shared value.
473 *
474 * Don't unset shared values (i.e., bail out) when the interpreter is
475 * being destroyed as that is a nasty side effect on other interpreters
476 * still using the shared value.
477 */
478
479 if (flags & TCL_INTERP_DESTROYED) {
480 valuePtr->shareCount--;
481 if (valuePtr->shareCount == 0) {
482 destroyed = 1;
483 Tcl_DeleteHashEntry(hPtr);
484 } else {
485 bail = 1;
486 }
487 }
488
489 /*
490 * The Tcl_UnsetVar calls in this procedure will trigger
491 * recursive unset traces, so if we detect this we just bail
492 */
493
494 if (valuePtr->flags & SHARE_TRACE) {
495 bail = 1;
496 }
497 Ns_CsLeave(&servPtr->share.cs);
498
499 if (bail) {
500 goto done;
501 }
502
503 Ns_CsEnter(&valuePtr->lock);
504
505 if ((flags & TCL_TRACE_ARRAY) && (valuePtr->flags & SHARE_ARRAY)) {
506 /*
507 * The easiest way to ensure our copy is up-to-date is just
508 * to delete it and recreate it from scratch. This makes
509 * the array names and array get operations weighty.
510 */
511
512 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareUnsetVar">ShareUnsetVar</a>(interp, name, valuePtr);
513 hPtr = Tcl_FirstHashEntry(&valuePtr->array, &search);
514 while (hPtr != NULL) {
515 name2 = Tcl_GetHashKey(&valuePtr->array, hPtr);
516 objPtr = Tcl_GetHashValue(hPtr);
517 Tcl_SetVar2Ex(interp, name, name2, Tcl_DuplicateObj(objPtr), 0);
518 hPtr = Tcl_NextHashEntry(&search);
519 }
520 }
521
522 if (flags & TCL_TRACE_WRITES) {
523
524 /*
525 * Get a copy of the variable value for the shared value.
526 */
527
528 objPtr = Tcl_GetVar2Ex(interp, name, name2, 0);
529 string = Tcl_GetStringFromObj(objPtr, &length);
530 newObjPtr = Tcl_NewStringObj(string, length);
531 Tcl_IncrRefCount(newObjPtr);
532 if (name2 != NULL) {
533 /*
534 * Update the shared value.
535 */
536
537 if (valuePtr->flags == SHARE_UNDEFINED) {
538 Tcl_InitHashTable(&valuePtr->array, TCL_STRING_KEYS);
539 valuePtr->flags = SHARE_ARRAY;
540 }
541 hPtr = Tcl_CreateHashEntry(&valuePtr->array, name2, &new);
542 oldObjPtr = (Tcl_Obj *) Tcl_GetHashValue(hPtr);
543 Tcl_SetHashValue(hPtr, (char *) newObjPtr);
544 } else {
545 oldObjPtr = valuePtr->objPtr;
546 valuePtr->objPtr = newObjPtr;
547 }
548
549 /*
550 * Discard the old shared value.
551 */
552
553 if (oldObjPtr != NULL) {
554 Tcl_DecrRefCount(oldObjPtr);
555 }
556 }
557
558 if (flags & TCL_TRACE_READS) {
559 objPtr = NULL;
560 if (name2 != NULL) {
561 hPtr = Tcl_FindHashEntry(&valuePtr->array, name2);
562 if (hPtr != NULL) {
563 objPtr = (Tcl_Obj *) Tcl_GetHashValue(hPtr);
564 }
565 } else if (valuePtr->objPtr != NULL) {
566 objPtr = valuePtr->objPtr;
567 }
568 if (objPtr != NULL) {
569 newObjPtr = Tcl_DuplicateObj(objPtr);
570 Tcl_SetVar2Ex(interp, name, name2, newObjPtr, 0);
571 }
572 }
573
574 if (flags & TCL_TRACE_UNSETS) {
575 /*
576 * Unset the corresponding shared value.
577 */
578
579 if (name2 != NULL) {
580 hPtr = Tcl_FindHashEntry(&valuePtr->array, name2);
581 if (hPtr != NULL) {
582 objPtr = Tcl_GetHashValue(hPtr);
583 Tcl_DecrRefCount(objPtr);
584 Tcl_DeleteHashEntry(hPtr);
585 }
586 } else if (valuePtr->flags & SHARE_ARRAY) {
587 hPtr = Tcl_FirstHashEntry(&valuePtr->array, &search);
588 while (hPtr != NULL) {
589 nextPtr = Tcl_NextHashEntry(&search);
590 objPtr = Tcl_GetHashValue(hPtr);
591 Tcl_DecrRefCount(objPtr);
592 Tcl_DeleteHashEntry(hPtr);
593 hPtr = nextPtr;
594 }
595 Tcl_DeleteHashTable(&valuePtr->array);
596 valuePtr->flags &= ~SHARE_ARRAY;
597 } else if (valuePtr->objPtr != NULL) {
598 Tcl_DecrRefCount(valuePtr->objPtr);
599 valuePtr->objPtr = NULL;
600 valuePtr->flags &= ~SHARE_SCALAR;
601 }
602 if (!destroyed) {
603 /*
604 * This makes the shared property of the variable "sticky"
605 * across unsets.
606 */
607
608 if (Tcl_TraceVar2(interp, name, (char *) NULL,
609 TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
610 TCL_TRACE_READS | TCL_TRACE_ARRAY, <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_ShareTraceProc">ShareTraceProc</a>,
611 (ClientData) NULL) != TCL_OK) {
612 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Fatal">Ns_Fatal</a>("Cannot set trace on share");
613 }
614 }
615 }
616
617 Ns_CsLeave(&valuePtr->lock);
618
619 /*
620 * Assert we are the only thread with a reference to this
621 * valuePtr, so we can delete it without holding its lock.
622 */
623
624 if (destroyed) {
625 Ns_CsDestroy(&valuePtr->lock);
626 Tcl_Free((char *) valuePtr );
627 }
628
629 done:
630 Tcl_DStringFree(&ds);
631 return NULL;
632 }
633
634
635 static char *
636 <a href="/cvs/aolserver/aolserver/nsd/tclshare.c#A_GetGlobalizedName">GetGlobalizedName</a>(Tcl_DString *dsPtr, char *varName)
637 {
638 Tcl_DStringInit(dsPtr);
639
640 if (strncmp("::", varName, 2) != 0) {
641 Tcl_DStringAppend(dsPtr, "::", 2);
642 }
643 Tcl_DStringAppend(dsPtr, varName, -1);
644 return dsPtr->string;
645 }