os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclPreserve.c
changeset 0 bde4ae8d615e
     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 +