os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclPreserve.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclPreserve.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,486 @@
1.4 +/*
1.5 + * tclPreserve.c --
1.6 + *
1.7 + * This file contains a collection of procedures that are used
1.8 + * to make sure that widget records and other data structures
1.9 + * aren't reallocated when there are nested procedures that
1.10 + * depend on their existence.
1.11 + *
1.12 + * Copyright (c) 1991-1994 The Regents of the University of California.
1.13 + * Copyright (c) 1994-1998 Sun Microsystems, Inc.
1.14 + * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
1.15 + *
1.16 + * See the file "license.terms" for information on usage and redistribution
1.17 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
1.18 + *
1.19 + * RCS: @(#) $Id: tclPreserve.c,v 1.3.34.2 2005/06/24 18:21:41 kennykb Exp $
1.20 + */
1.21 +
1.22 +#include "tclInt.h"
1.23 +
1.24 +/*
1.25 + * The following data structure is used to keep track of all the
1.26 + * Tcl_Preserve calls that are still in effect. It grows as needed
1.27 + * to accommodate any number of calls in effect.
1.28 + */
1.29 +
1.30 +typedef struct {
1.31 + ClientData clientData; /* Address of preserved block. */
1.32 + int refCount; /* Number of Tcl_Preserve calls in effect
1.33 + * for block. */
1.34 + int mustFree; /* Non-zero means Tcl_EventuallyFree was
1.35 + * called while a Tcl_Preserve call was in
1.36 + * effect, so the structure must be freed
1.37 + * when refCount becomes zero. */
1.38 + Tcl_FreeProc *freeProc; /* Procedure to call to free. */
1.39 +} Reference;
1.40 +
1.41 +#if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
1.42 +static Reference *refArray; /* First in array of references. */
1.43 +static int spaceAvl = 0; /* Total number of structures available
1.44 + * at *firstRefPtr. */
1.45 +static int inUse = 0; /* Count of structures currently in use
1.46 + * in refArray. */
1.47 +#else
1.48 +#define refArray (*(Reference**)get_refArray())
1.49 +#define spaceAvl (*(int *)get_spaceAvl())
1.50 +#define inUse (*(int *)get_inUse())
1.51 +#endif
1.52 +#define INITIAL_SIZE 2
1.53 +TCL_DECLARE_MUTEX(preserveMutex)/* To protect the above statics */
1.54 +
1.55 +/*
1.56 + * The following data structure is used to keep track of whether an
1.57 + * arbitrary block of memory has been deleted. This is used by the
1.58 + * TclHandle code to avoid the more time-expensive algorithm of
1.59 + * Tcl_Preserve(). This mechanism is mainly used when we have lots of
1.60 + * references to a few big, expensive objects that we don't want to live
1.61 + * any longer than necessary.
1.62 + */
1.63 +
1.64 +typedef struct HandleStruct {
1.65 + VOID *ptr; /* Pointer to the memory block being
1.66 + * tracked. This field will become NULL when
1.67 + * the memory block is deleted. This field
1.68 + * must be the first in the structure. */
1.69 +#ifdef TCL_MEM_DEBUG
1.70 + VOID *ptr2; /* Backup copy of the abpve pointer used to
1.71 + * ensure that the contents of the handle are
1.72 + * not changed by anyone else. */
1.73 +#endif
1.74 + int refCount; /* Number of TclHandlePreserve() calls in
1.75 + * effect on this handle. */
1.76 +} HandleStruct;
1.77 +
1.78 +
1.79 +
1.80 +/*
1.81 + *----------------------------------------------------------------------
1.82 + *
1.83 + * TclFinalizePreserve --
1.84 + *
1.85 + * Called during exit processing to clean up the reference array.
1.86 + *
1.87 + * Results:
1.88 + * None.
1.89 + *
1.90 + * Side effects:
1.91 + * Frees the storage of the reference array.
1.92 + *
1.93 + *----------------------------------------------------------------------
1.94 + */
1.95 +
1.96 + /* ARGSUSED */
1.97 +void
1.98 +TclFinalizePreserve()
1.99 +{
1.100 + Tcl_MutexLock(&preserveMutex);
1.101 + if (spaceAvl != 0) {
1.102 + ckfree((char *) refArray);
1.103 + refArray = (Reference *) NULL;
1.104 + inUse = 0;
1.105 + spaceAvl = 0;
1.106 + }
1.107 + Tcl_MutexUnlock(&preserveMutex);
1.108 +}
1.109 +
1.110 +/*
1.111 + *----------------------------------------------------------------------
1.112 + *
1.113 + * Tcl_Preserve --
1.114 + *
1.115 + * This procedure is used by a procedure to declare its interest
1.116 + * in a particular block of memory, so that the block will not be
1.117 + * reallocated until a matching call to Tcl_Release has been made.
1.118 + *
1.119 + * Results:
1.120 + * None.
1.121 + *
1.122 + * Side effects:
1.123 + * Information is retained so that the block of memory will
1.124 + * not be freed until at least the matching call to Tcl_Release.
1.125 + *
1.126 + *----------------------------------------------------------------------
1.127 + */
1.128 +
1.129 +EXPORT_C void
1.130 +Tcl_Preserve(clientData)
1.131 + ClientData clientData; /* Pointer to malloc'ed block of memory. */
1.132 +{
1.133 + Reference *refPtr;
1.134 + int i;
1.135 +
1.136 + /*
1.137 + * See if there is already a reference for this pointer. If so,
1.138 + * just increment its reference count.
1.139 + */
1.140 +
1.141 + Tcl_MutexLock(&preserveMutex);
1.142 + for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
1.143 + if (refPtr->clientData == clientData) {
1.144 + refPtr->refCount++;
1.145 + Tcl_MutexUnlock(&preserveMutex);
1.146 + return;
1.147 + }
1.148 + }
1.149 +
1.150 + /*
1.151 + * Make a reference array if it doesn't already exist, or make it
1.152 + * bigger if it is full.
1.153 + */
1.154 +
1.155 + if (inUse == spaceAvl) {
1.156 + if (spaceAvl == 0) {
1.157 + refArray = (Reference *) ckalloc((unsigned)
1.158 + (INITIAL_SIZE*sizeof(Reference)));
1.159 + spaceAvl = INITIAL_SIZE;
1.160 + } else {
1.161 + Reference *new;
1.162 +
1.163 + new = (Reference *) ckalloc((unsigned)
1.164 + (2*spaceAvl*sizeof(Reference)));
1.165 + memcpy((VOID *) new, (VOID *) refArray,
1.166 + spaceAvl*sizeof(Reference));
1.167 + ckfree((char *) refArray);
1.168 + refArray = new;
1.169 + spaceAvl *= 2;
1.170 + }
1.171 + }
1.172 +
1.173 + /*
1.174 + * Make a new entry for the new reference.
1.175 + */
1.176 +
1.177 + refPtr = &refArray[inUse];
1.178 + refPtr->clientData = clientData;
1.179 + refPtr->refCount = 1;
1.180 + refPtr->mustFree = 0;
1.181 + refPtr->freeProc = TCL_STATIC;
1.182 + inUse += 1;
1.183 + Tcl_MutexUnlock(&preserveMutex);
1.184 +}
1.185 +
1.186 +/*
1.187 + *----------------------------------------------------------------------
1.188 + *
1.189 + * Tcl_Release --
1.190 + *
1.191 + * This procedure is called to cancel a previous call to
1.192 + * Tcl_Preserve, thereby allowing a block of memory to be
1.193 + * freed (if no one else cares about it).
1.194 + *
1.195 + * Results:
1.196 + * None.
1.197 + *
1.198 + * Side effects:
1.199 + * If Tcl_EventuallyFree has been called for clientData, and if
1.200 + * no other call to Tcl_Preserve is still in effect, the block of
1.201 + * memory is freed.
1.202 + *
1.203 + *----------------------------------------------------------------------
1.204 + */
1.205 +
1.206 +EXPORT_C void
1.207 +Tcl_Release(clientData)
1.208 + ClientData clientData; /* Pointer to malloc'ed block of memory. */
1.209 +{
1.210 + Reference *refPtr;
1.211 + int mustFree;
1.212 + Tcl_FreeProc *freeProc;
1.213 + int i;
1.214 +
1.215 + Tcl_MutexLock(&preserveMutex);
1.216 + for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
1.217 + if (refPtr->clientData != clientData) {
1.218 + continue;
1.219 + }
1.220 + refPtr->refCount--;
1.221 + if (refPtr->refCount == 0) {
1.222 +
1.223 + /*
1.224 + * Must remove information from the slot before calling freeProc
1.225 + * to avoid reentrancy problems if the freeProc calls Tcl_Preserve
1.226 + * on the same clientData. Copy down the last reference in the
1.227 + * array to overwrite the current slot.
1.228 + */
1.229 +
1.230 + freeProc = refPtr->freeProc;
1.231 + mustFree = refPtr->mustFree;
1.232 + inUse--;
1.233 + if (i < inUse) {
1.234 + refArray[i] = refArray[inUse];
1.235 + }
1.236 + if (mustFree) {
1.237 + if (freeProc == TCL_DYNAMIC) {
1.238 + ckfree((char *) clientData);
1.239 + } else {
1.240 + Tcl_MutexUnlock(&preserveMutex);
1.241 + (*freeProc)((char *) clientData);
1.242 + return;
1.243 + }
1.244 + }
1.245 + }
1.246 + Tcl_MutexUnlock(&preserveMutex);
1.247 + return;
1.248 + }
1.249 + Tcl_MutexUnlock(&preserveMutex);
1.250 +
1.251 + /*
1.252 + * Reference not found. This is a bug in the caller.
1.253 + */
1.254 +
1.255 + panic("Tcl_Release couldn't find reference for 0x%x", clientData);
1.256 +}
1.257 +
1.258 +/*
1.259 + *----------------------------------------------------------------------
1.260 + *
1.261 + * Tcl_EventuallyFree --
1.262 + *
1.263 + * Free up a block of memory, unless a call to Tcl_Preserve is in
1.264 + * effect for that block. In this case, defer the free until all
1.265 + * calls to Tcl_Preserve have been undone by matching calls to
1.266 + * Tcl_Release.
1.267 + *
1.268 + * Results:
1.269 + * None.
1.270 + *
1.271 + * Side effects:
1.272 + * Ptr may be released by calling free().
1.273 + *
1.274 + *----------------------------------------------------------------------
1.275 + */
1.276 +
1.277 +EXPORT_C void
1.278 +Tcl_EventuallyFree(clientData, freeProc)
1.279 + ClientData clientData; /* Pointer to malloc'ed block of memory. */
1.280 + Tcl_FreeProc *freeProc; /* Procedure to actually do free. */
1.281 +{
1.282 + Reference *refPtr;
1.283 + int i;
1.284 +
1.285 + /*
1.286 + * See if there is a reference for this pointer. If so, set its
1.287 + * "mustFree" flag (the flag had better not be set already!).
1.288 + */
1.289 +
1.290 + Tcl_MutexLock(&preserveMutex);
1.291 + for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
1.292 + if (refPtr->clientData != clientData) {
1.293 + continue;
1.294 + }
1.295 + if (refPtr->mustFree) {
1.296 + panic("Tcl_EventuallyFree called twice for 0x%x\n", clientData);
1.297 + }
1.298 + refPtr->mustFree = 1;
1.299 + refPtr->freeProc = freeProc;
1.300 + Tcl_MutexUnlock(&preserveMutex);
1.301 + return;
1.302 + }
1.303 + Tcl_MutexUnlock(&preserveMutex);
1.304 +
1.305 + /*
1.306 + * No reference for this block. Free it now.
1.307 + */
1.308 +
1.309 + if (freeProc == TCL_DYNAMIC) {
1.310 + ckfree((char *) clientData);
1.311 + } else {
1.312 + (*freeProc)((char *)clientData);
1.313 + }
1.314 +}
1.315 +
1.316 +/*
1.317 + *---------------------------------------------------------------------------
1.318 + *
1.319 + * TclHandleCreate --
1.320 + *
1.321 + * Allocate a handle that contains enough information to determine
1.322 + * if an arbitrary malloc'd block has been deleted. This is
1.323 + * used to avoid the more time-expensive algorithm of Tcl_Preserve().
1.324 + *
1.325 + * Results:
1.326 + * The return value is a TclHandle that refers to the given malloc'd
1.327 + * block. Doubly dereferencing the returned handle will give
1.328 + * back the pointer to the block, or will give NULL if the block has
1.329 + * been deleted.
1.330 + *
1.331 + * Side effects:
1.332 + * The caller must keep track of this handle (generally by storing
1.333 + * it in a field in the malloc'd block) and call TclHandleFree()
1.334 + * on this handle when the block is deleted. Everything else that
1.335 + * wishes to keep track of whether the malloc'd block has been deleted
1.336 + * should use calls to TclHandlePreserve() and TclHandleRelease()
1.337 + * on the associated handle.
1.338 + *
1.339 + *---------------------------------------------------------------------------
1.340 + */
1.341 +
1.342 +TclHandle
1.343 +TclHandleCreate(ptr)
1.344 + VOID *ptr; /* Pointer to an arbitrary block of memory
1.345 + * to be tracked for deletion. Must not be
1.346 + * NULL. */
1.347 +{
1.348 + HandleStruct *handlePtr;
1.349 +
1.350 + handlePtr = (HandleStruct *) ckalloc(sizeof(HandleStruct));
1.351 + handlePtr->ptr = ptr;
1.352 +#ifdef TCL_MEM_DEBUG
1.353 + handlePtr->ptr2 = ptr;
1.354 +#endif
1.355 + handlePtr->refCount = 0;
1.356 + return (TclHandle) handlePtr;
1.357 +}
1.358 +
1.359 +/*
1.360 + *---------------------------------------------------------------------------
1.361 + *
1.362 + * TclHandleFree --
1.363 + *
1.364 + * Called when the arbitrary malloc'd block associated with the
1.365 + * handle is being deleted. Modifies the handle so that doubly
1.366 + * dereferencing it will give NULL. This informs any user of the
1.367 + * handle that the block of memory formerly referenced by the
1.368 + * handle has been freed.
1.369 + *
1.370 + * Results:
1.371 + * None.
1.372 + *
1.373 + * Side effects:
1.374 + * If nothing is referring to the handle, the handle will be reclaimed.
1.375 + *
1.376 + *---------------------------------------------------------------------------
1.377 + */
1.378 +
1.379 +void
1.380 +TclHandleFree(handle)
1.381 + TclHandle handle; /* Previously created handle associated
1.382 + * with a malloc'd block that is being
1.383 + * deleted. The handle is modified so that
1.384 + * doubly dereferencing it will give NULL. */
1.385 +{
1.386 + HandleStruct *handlePtr;
1.387 +
1.388 + handlePtr = (HandleStruct *) handle;
1.389 +#ifdef TCL_MEM_DEBUG
1.390 + if (handlePtr->refCount == 0x61616161) {
1.391 + panic("using previously disposed TclHandle %x", handlePtr);
1.392 + }
1.393 + if (handlePtr->ptr2 != handlePtr->ptr) {
1.394 + panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
1.395 + handlePtr, handlePtr->ptr2, handlePtr->ptr);
1.396 + }
1.397 +#endif
1.398 + handlePtr->ptr = NULL;
1.399 + if (handlePtr->refCount == 0) {
1.400 + ckfree((char *) handlePtr);
1.401 + }
1.402 +}
1.403 +
1.404 +/*
1.405 + *---------------------------------------------------------------------------
1.406 + *
1.407 + * TclHandlePreserve --
1.408 + *
1.409 + * Declare an interest in the arbitrary malloc'd block associated
1.410 + * with the handle.
1.411 + *
1.412 + * Results:
1.413 + * The return value is the handle argument, with its ref count
1.414 + * incremented.
1.415 + *
1.416 + * Side effects:
1.417 + * For each call to TclHandlePreserve(), there should be a matching
1.418 + * call to TclHandleRelease() when the caller is no longer interested
1.419 + * in the malloc'd block associated with the handle.
1.420 + *
1.421 + *---------------------------------------------------------------------------
1.422 + */
1.423 +
1.424 +TclHandle
1.425 +TclHandlePreserve(handle)
1.426 + TclHandle handle; /* Declare an interest in the block of
1.427 + * memory referenced by this handle. */
1.428 +{
1.429 + HandleStruct *handlePtr;
1.430 +
1.431 + handlePtr = (HandleStruct *) handle;
1.432 +#ifdef TCL_MEM_DEBUG
1.433 + if (handlePtr->refCount == 0x61616161) {
1.434 + panic("using previously disposed TclHandle %x", handlePtr);
1.435 + }
1.436 + if ((handlePtr->ptr != NULL)
1.437 + && (handlePtr->ptr != handlePtr->ptr2)) {
1.438 + panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
1.439 + handlePtr, handlePtr->ptr2, handlePtr->ptr);
1.440 + }
1.441 +#endif
1.442 + handlePtr->refCount++;
1.443 +
1.444 + return handle;
1.445 +}
1.446 +
1.447 +/*
1.448 + *---------------------------------------------------------------------------
1.449 + *
1.450 + * TclHandleRelease --
1.451 + *
1.452 + * This procedure is called to release an interest in the malloc'd
1.453 + * block associated with the handle.
1.454 + *
1.455 + * Results:
1.456 + * None.
1.457 + *
1.458 + * Side effects:
1.459 + * The ref count of the handle is decremented. If the malloc'd block
1.460 + * has been freed and if no one is using the handle any more, the
1.461 + * handle will be reclaimed.
1.462 + *
1.463 + *---------------------------------------------------------------------------
1.464 + */
1.465 +
1.466 +void
1.467 +TclHandleRelease(handle)
1.468 + TclHandle handle; /* Unregister interest in the block of
1.469 + * memory referenced by this handle. */
1.470 +{
1.471 + HandleStruct *handlePtr;
1.472 +
1.473 + handlePtr = (HandleStruct *) handle;
1.474 +#ifdef TCL_MEM_DEBUG
1.475 + if (handlePtr->refCount == 0x61616161) {
1.476 + panic("using previously disposed TclHandle %x", handlePtr);
1.477 + }
1.478 + if ((handlePtr->ptr != NULL)
1.479 + && (handlePtr->ptr != handlePtr->ptr2)) {
1.480 + panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
1.481 + handlePtr, handlePtr->ptr2, handlePtr->ptr);
1.482 + }
1.483 +#endif
1.484 + handlePtr->refCount--;
1.485 + if ((handlePtr->refCount == 0) && (handlePtr->ptr == NULL)) {
1.486 + ckfree((char *) handlePtr);
1.487 + }
1.488 +}
1.489 +