|
|
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.