os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclPreserve.c
Update contrib.
4 * This file contains a collection of procedures that are used
5 * to make sure that widget records and other data structures
6 * aren't reallocated when there are nested procedures that
7 * depend on their existence.
9 * Copyright (c) 1991-1994 The Regents of the University of California.
10 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
11 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
13 * See the file "license.terms" for information on usage and redistribution
14 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 * RCS: @(#) $Id: tclPreserve.c,v 1.3.34.2 2005/06/24 18:21:41 kennykb Exp $
22 * The following data structure is used to keep track of all the
23 * Tcl_Preserve calls that are still in effect. It grows as needed
24 * to accommodate any number of calls in effect.
28 ClientData clientData; /* Address of preserved block. */
29 int refCount; /* Number of Tcl_Preserve calls in effect
31 int mustFree; /* Non-zero means Tcl_EventuallyFree was
32 * called while a Tcl_Preserve call was in
33 * effect, so the structure must be freed
34 * when refCount becomes zero. */
35 Tcl_FreeProc *freeProc; /* Procedure to call to free. */
38 #if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
39 static Reference *refArray; /* First in array of references. */
40 static int spaceAvl = 0; /* Total number of structures available
42 static int inUse = 0; /* Count of structures currently in use
45 #define refArray (*(Reference**)get_refArray())
46 #define spaceAvl (*(int *)get_spaceAvl())
47 #define inUse (*(int *)get_inUse())
49 #define INITIAL_SIZE 2
50 TCL_DECLARE_MUTEX(preserveMutex)/* To protect the above statics */
53 * The following data structure is used to keep track of whether an
54 * arbitrary block of memory has been deleted. This is used by the
55 * TclHandle code to avoid the more time-expensive algorithm of
56 * Tcl_Preserve(). This mechanism is mainly used when we have lots of
57 * references to a few big, expensive objects that we don't want to live
58 * any longer than necessary.
61 typedef struct HandleStruct {
62 VOID *ptr; /* Pointer to the memory block being
63 * tracked. This field will become NULL when
64 * the memory block is deleted. This field
65 * must be the first in the structure. */
67 VOID *ptr2; /* Backup copy of the abpve pointer used to
68 * ensure that the contents of the handle are
69 * not changed by anyone else. */
71 int refCount; /* Number of TclHandlePreserve() calls in
72 * effect on this handle. */
78 *----------------------------------------------------------------------
80 * TclFinalizePreserve --
82 * Called during exit processing to clean up the reference array.
88 * Frees the storage of the reference array.
90 *----------------------------------------------------------------------
97 Tcl_MutexLock(&preserveMutex);
99 ckfree((char *) refArray);
100 refArray = (Reference *) NULL;
104 Tcl_MutexUnlock(&preserveMutex);
108 *----------------------------------------------------------------------
112 * This procedure is used by a procedure to declare its interest
113 * in a particular block of memory, so that the block will not be
114 * reallocated until a matching call to Tcl_Release has been made.
120 * Information is retained so that the block of memory will
121 * not be freed until at least the matching call to Tcl_Release.
123 *----------------------------------------------------------------------
127 Tcl_Preserve(clientData)
128 ClientData clientData; /* Pointer to malloc'ed block of memory. */
134 * See if there is already a reference for this pointer. If so,
135 * just increment its reference count.
138 Tcl_MutexLock(&preserveMutex);
139 for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
140 if (refPtr->clientData == clientData) {
142 Tcl_MutexUnlock(&preserveMutex);
148 * Make a reference array if it doesn't already exist, or make it
149 * bigger if it is full.
152 if (inUse == spaceAvl) {
154 refArray = (Reference *) ckalloc((unsigned)
155 (INITIAL_SIZE*sizeof(Reference)));
156 spaceAvl = INITIAL_SIZE;
160 new = (Reference *) ckalloc((unsigned)
161 (2*spaceAvl*sizeof(Reference)));
162 memcpy((VOID *) new, (VOID *) refArray,
163 spaceAvl*sizeof(Reference));
164 ckfree((char *) refArray);
171 * Make a new entry for the new reference.
174 refPtr = &refArray[inUse];
175 refPtr->clientData = clientData;
176 refPtr->refCount = 1;
177 refPtr->mustFree = 0;
178 refPtr->freeProc = TCL_STATIC;
180 Tcl_MutexUnlock(&preserveMutex);
184 *----------------------------------------------------------------------
188 * This procedure is called to cancel a previous call to
189 * Tcl_Preserve, thereby allowing a block of memory to be
190 * freed (if no one else cares about it).
196 * If Tcl_EventuallyFree has been called for clientData, and if
197 * no other call to Tcl_Preserve is still in effect, the block of
200 *----------------------------------------------------------------------
204 Tcl_Release(clientData)
205 ClientData clientData; /* Pointer to malloc'ed block of memory. */
209 Tcl_FreeProc *freeProc;
212 Tcl_MutexLock(&preserveMutex);
213 for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
214 if (refPtr->clientData != clientData) {
218 if (refPtr->refCount == 0) {
221 * Must remove information from the slot before calling freeProc
222 * to avoid reentrancy problems if the freeProc calls Tcl_Preserve
223 * on the same clientData. Copy down the last reference in the
224 * array to overwrite the current slot.
227 freeProc = refPtr->freeProc;
228 mustFree = refPtr->mustFree;
231 refArray[i] = refArray[inUse];
234 if (freeProc == TCL_DYNAMIC) {
235 ckfree((char *) clientData);
237 Tcl_MutexUnlock(&preserveMutex);
238 (*freeProc)((char *) clientData);
243 Tcl_MutexUnlock(&preserveMutex);
246 Tcl_MutexUnlock(&preserveMutex);
249 * Reference not found. This is a bug in the caller.
252 panic("Tcl_Release couldn't find reference for 0x%x", clientData);
256 *----------------------------------------------------------------------
258 * Tcl_EventuallyFree --
260 * Free up a block of memory, unless a call to Tcl_Preserve is in
261 * effect for that block. In this case, defer the free until all
262 * calls to Tcl_Preserve have been undone by matching calls to
269 * Ptr may be released by calling free().
271 *----------------------------------------------------------------------
275 Tcl_EventuallyFree(clientData, freeProc)
276 ClientData clientData; /* Pointer to malloc'ed block of memory. */
277 Tcl_FreeProc *freeProc; /* Procedure to actually do free. */
283 * See if there is a reference for this pointer. If so, set its
284 * "mustFree" flag (the flag had better not be set already!).
287 Tcl_MutexLock(&preserveMutex);
288 for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
289 if (refPtr->clientData != clientData) {
292 if (refPtr->mustFree) {
293 panic("Tcl_EventuallyFree called twice for 0x%x\n", clientData);
295 refPtr->mustFree = 1;
296 refPtr->freeProc = freeProc;
297 Tcl_MutexUnlock(&preserveMutex);
300 Tcl_MutexUnlock(&preserveMutex);
303 * No reference for this block. Free it now.
306 if (freeProc == TCL_DYNAMIC) {
307 ckfree((char *) clientData);
309 (*freeProc)((char *)clientData);
314 *---------------------------------------------------------------------------
318 * Allocate a handle that contains enough information to determine
319 * if an arbitrary malloc'd block has been deleted. This is
320 * used to avoid the more time-expensive algorithm of Tcl_Preserve().
323 * The return value is a TclHandle that refers to the given malloc'd
324 * block. Doubly dereferencing the returned handle will give
325 * back the pointer to the block, or will give NULL if the block has
329 * The caller must keep track of this handle (generally by storing
330 * it in a field in the malloc'd block) and call TclHandleFree()
331 * on this handle when the block is deleted. Everything else that
332 * wishes to keep track of whether the malloc'd block has been deleted
333 * should use calls to TclHandlePreserve() and TclHandleRelease()
334 * on the associated handle.
336 *---------------------------------------------------------------------------
341 VOID *ptr; /* Pointer to an arbitrary block of memory
342 * to be tracked for deletion. Must not be
345 HandleStruct *handlePtr;
347 handlePtr = (HandleStruct *) ckalloc(sizeof(HandleStruct));
348 handlePtr->ptr = ptr;
350 handlePtr->ptr2 = ptr;
352 handlePtr->refCount = 0;
353 return (TclHandle) handlePtr;
357 *---------------------------------------------------------------------------
361 * Called when the arbitrary malloc'd block associated with the
362 * handle is being deleted. Modifies the handle so that doubly
363 * dereferencing it will give NULL. This informs any user of the
364 * handle that the block of memory formerly referenced by the
365 * handle has been freed.
371 * If nothing is referring to the handle, the handle will be reclaimed.
373 *---------------------------------------------------------------------------
377 TclHandleFree(handle)
378 TclHandle handle; /* Previously created handle associated
379 * with a malloc'd block that is being
380 * deleted. The handle is modified so that
381 * doubly dereferencing it will give NULL. */
383 HandleStruct *handlePtr;
385 handlePtr = (HandleStruct *) handle;
387 if (handlePtr->refCount == 0x61616161) {
388 panic("using previously disposed TclHandle %x", handlePtr);
390 if (handlePtr->ptr2 != handlePtr->ptr) {
391 panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
392 handlePtr, handlePtr->ptr2, handlePtr->ptr);
395 handlePtr->ptr = NULL;
396 if (handlePtr->refCount == 0) {
397 ckfree((char *) handlePtr);
402 *---------------------------------------------------------------------------
404 * TclHandlePreserve --
406 * Declare an interest in the arbitrary malloc'd block associated
410 * The return value is the handle argument, with its ref count
414 * For each call to TclHandlePreserve(), there should be a matching
415 * call to TclHandleRelease() when the caller is no longer interested
416 * in the malloc'd block associated with the handle.
418 *---------------------------------------------------------------------------
422 TclHandlePreserve(handle)
423 TclHandle handle; /* Declare an interest in the block of
424 * memory referenced by this handle. */
426 HandleStruct *handlePtr;
428 handlePtr = (HandleStruct *) handle;
430 if (handlePtr->refCount == 0x61616161) {
431 panic("using previously disposed TclHandle %x", handlePtr);
433 if ((handlePtr->ptr != NULL)
434 && (handlePtr->ptr != handlePtr->ptr2)) {
435 panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
436 handlePtr, handlePtr->ptr2, handlePtr->ptr);
439 handlePtr->refCount++;
445 *---------------------------------------------------------------------------
447 * TclHandleRelease --
449 * This procedure is called to release an interest in the malloc'd
450 * block associated with the handle.
456 * The ref count of the handle is decremented. If the malloc'd block
457 * has been freed and if no one is using the handle any more, the
458 * handle will be reclaimed.
460 *---------------------------------------------------------------------------
464 TclHandleRelease(handle)
465 TclHandle handle; /* Unregister interest in the block of
466 * memory referenced by this handle. */
468 HandleStruct *handlePtr;
470 handlePtr = (HandleStruct *) handle;
472 if (handlePtr->refCount == 0x61616161) {
473 panic("using previously disposed TclHandle %x", handlePtr);
475 if ((handlePtr->ptr != NULL)
476 && (handlePtr->ptr != handlePtr->ptr2)) {
477 panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
478 handlePtr, handlePtr->ptr2, handlePtr->ptr);
481 handlePtr->refCount--;
482 if ((handlePtr->refCount == 0) && (handlePtr->ptr == NULL)) {
483 ckfree((char *) handlePtr);