|
|
1.1 ! root 1: /* ! 2: * tkPreserve.c -- ! 3: * ! 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. ! 8: * ! 9: * Copyright 1991 Regents of the University of California ! 10: * Permission to use, copy, modify, and distribute this ! 11: * software and its documentation for any purpose and without ! 12: * fee is hereby granted, provided that this copyright ! 13: * notice appears in all copies. The University of California ! 14: * makes no representations about the suitability of this ! 15: * software for any purpose. It is provided "as is" without ! 16: * express or implied warranty. ! 17: */ ! 18: ! 19: #ifndef lint ! 20: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkPreserve.c,v 1.6 92/06/15 13:44:51 ouster Exp $ SPRITE (Berkeley)"; ! 21: #endif /* not lint */ ! 22: ! 23: #include "tkconfig.h" ! 24: #include "tk.h" ! 25: ! 26: /* ! 27: * The following data structure is used to keep track of all the ! 28: * Tk_Preserve calls that are still in effect. It grows as needed ! 29: * to accommodate any number of calls in effect. ! 30: */ ! 31: ! 32: typedef struct { ! 33: ClientData clientData; /* Address of preserved block. */ ! 34: int refCount; /* Number of Tk_Preserve calls in effect ! 35: * for block. */ ! 36: int mustFree; /* Non-zero means Tk_EventuallyFree was ! 37: * called while a Tk_Preserve call was in ! 38: * effect, so the structure must be freed ! 39: * when refCount becomes zero. */ ! 40: Tk_FreeProc *freeProc; /* Procedure to call to free. */ ! 41: } Reference; ! 42: ! 43: static Reference *refArray; /* First in array of references. */ ! 44: static int spaceAvl = 0; /* Total number of structures available ! 45: * at *firstRefPtr. */ ! 46: static int inUse = 0; /* Count of structures currently in use ! 47: * in refArray. */ ! 48: #define INITIAL_SIZE 2 ! 49: ! 50: /* ! 51: *---------------------------------------------------------------------- ! 52: * ! 53: * Tk_Preserve -- ! 54: * ! 55: * This procedure is used by a procedure to declare its interest ! 56: * in a particular block of memory, so that the block will not be ! 57: * reallocated until a matching call to Tk_Release has been made. ! 58: * ! 59: * Results: ! 60: * None. ! 61: * ! 62: * Side effects: ! 63: * Information is retained so that the block of memory will ! 64: * not be freed until at least the matching call to Tk_Release. ! 65: * ! 66: *---------------------------------------------------------------------- ! 67: */ ! 68: ! 69: void ! 70: Tk_Preserve(clientData) ! 71: ClientData clientData; /* Pointer to malloc'ed block of memory. */ ! 72: { ! 73: register Reference *refPtr; ! 74: int i; ! 75: ! 76: /* ! 77: * See if there is already a reference for this pointer. If so, ! 78: * just increment its reference count. ! 79: */ ! 80: ! 81: for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) { ! 82: if (refPtr->clientData == clientData) { ! 83: refPtr->refCount++; ! 84: return; ! 85: } ! 86: } ! 87: ! 88: /* ! 89: * Make a reference array if it doesn't already exist, or make it ! 90: * bigger if it is full. ! 91: */ ! 92: ! 93: if (inUse == spaceAvl) { ! 94: if (spaceAvl == 0) { ! 95: refArray = (Reference *) ckalloc((unsigned) ! 96: (INITIAL_SIZE*sizeof(Reference))); ! 97: spaceAvl = INITIAL_SIZE; ! 98: } else { ! 99: Reference *new; ! 100: ! 101: new = (Reference *) ckalloc((unsigned) ! 102: (2*spaceAvl*sizeof(Reference))); ! 103: memcpy((VOID *) new, (VOID *) refArray, spaceAvl*sizeof(Reference)); ! 104: ckfree((char *) refArray); ! 105: refArray = new; ! 106: spaceAvl *= 2; ! 107: } ! 108: } ! 109: ! 110: /* ! 111: * Make a new entry for the new reference. ! 112: */ ! 113: ! 114: refPtr = &refArray[inUse]; ! 115: refPtr->clientData = clientData; ! 116: refPtr->refCount = 1; ! 117: refPtr->mustFree = 0; ! 118: inUse += 1; ! 119: } ! 120: ! 121: /* ! 122: *---------------------------------------------------------------------- ! 123: * ! 124: * Tk_Release -- ! 125: * ! 126: * This procedure is called to cancel a previous call to ! 127: * Tk_Preserve, thereby allowing a block of memory to be ! 128: * freed (if no one else cares about it). ! 129: * ! 130: * Results: ! 131: * None. ! 132: * ! 133: * Side effects: ! 134: * If Tk_EventuallyFree has been called for clientData, and if ! 135: * no other call to Tk_Preserve is still in effect, the block of ! 136: * memory is freed. ! 137: * ! 138: *---------------------------------------------------------------------- ! 139: */ ! 140: ! 141: void ! 142: Tk_Release(clientData) ! 143: ClientData clientData; /* Pointer to malloc'ed block of memory. */ ! 144: { ! 145: register Reference *refPtr; ! 146: int i; ! 147: ! 148: for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) { ! 149: if (refPtr->clientData != clientData) { ! 150: continue; ! 151: } ! 152: refPtr->refCount--; ! 153: if (refPtr->refCount == 0) { ! 154: if (refPtr->mustFree) { ! 155: if (refPtr->freeProc == (Tk_FreeProc *) free) { ! 156: ckfree((char *) refPtr->clientData); ! 157: } else { ! 158: (*refPtr->freeProc)(refPtr->clientData); ! 159: } ! 160: } ! 161: ! 162: /* ! 163: * Copy down all of the trailing reference in the array ! 164: * to cover up the hole left by the unused reference. ! 165: */ ! 166: ! 167: inUse--; ! 168: if (i != inUse) { ! 169: memcpy((VOID *) &refArray[i], (VOID *) &refArray[i+1], ! 170: (inUse-i)*sizeof(Reference)); ! 171: } ! 172: } ! 173: return; ! 174: } ! 175: ! 176: /* ! 177: * Reference not found. This is a bug in the caller. ! 178: */ ! 179: ! 180: panic("Tk_Release couldn't find reference for 0x%x", clientData); ! 181: } ! 182: ! 183: /* ! 184: *---------------------------------------------------------------------- ! 185: * ! 186: * Tk_EventuallyFree -- ! 187: * ! 188: * Free up a block of memory, unless a call to Tk_Preserve is in ! 189: * effect for that block. In this case, defer the free until all ! 190: * calls to Tk_Preserve have been undone by matching calls to ! 191: * Tk_Release. ! 192: * ! 193: * Results: ! 194: * None. ! 195: * ! 196: * Side effects: ! 197: * Ptr may be released by calling free(). ! 198: * ! 199: *---------------------------------------------------------------------- ! 200: */ ! 201: ! 202: void ! 203: Tk_EventuallyFree(clientData, freeProc) ! 204: ClientData clientData; /* Pointer to malloc'ed block of memory. */ ! 205: Tk_FreeProc *freeProc; /* Procedure to actually do free. */ ! 206: { ! 207: register Reference *refPtr; ! 208: int i; ! 209: ! 210: /* ! 211: * See if there is a reference for this pointer. If so, set its ! 212: * "mustFree" flag (the flag had better not be set already!). ! 213: */ ! 214: ! 215: for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) { ! 216: if (refPtr->clientData != clientData) { ! 217: continue; ! 218: } ! 219: if (refPtr->mustFree) { ! 220: panic("Tk_EventuallyFree called twice for 0x%x\n", clientData); ! 221: } ! 222: refPtr->mustFree = 1; ! 223: refPtr->freeProc = freeProc; ! 224: return; ! 225: } ! 226: ! 227: /* ! 228: * No reference for this block. Free it now. ! 229: */ ! 230: ! 231: if (freeProc == (Tk_FreeProc *) free) { ! 232: ckfree((char *) clientData); ! 233: } else { ! 234: (*freeProc)(clientData); ! 235: } ! 236: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.