]> git.zerfleddert.de Git - micropolis/blob - src/tk/tkpresrv.c
Import Micropolis from http://www.donhopkins.com/home/micropolis/
[micropolis] / src / tk / tkpresrv.c
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 \f
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 \f
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 \f
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 }
Impressum, Datenschutz