1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: gsmemlok.c 8721 2008-05-09 02:18:14Z ray $ */
15 /* Monitor-locked heap memory allocator */
16
17 /* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
18 /* Revised 8/6/98 by L. Peter Deutsch (ghost@aladdin.com) for changes */
19 /* in memory manager API */
20 /* Edited 3/23/1999 by L. Peter Deutsch to remove compiler warnings. */
21
22 #include "gx.h"
23 #include "gsmemlok.h"
24 #include "gserrors.h"
25
26 /* Raw memory procedures */
27 static gs_memory_proc_alloc_bytes(gs_locked_alloc_bytes_immovable);
28 static gs_memory_proc_resize_object(gs_locked_resize_object);
29 static gs_memory_proc_free_object(gs_locked_free_object);
30 static gs_memory_proc_stable(gs_locked_stable);
31 static gs_memory_proc_status(gs_locked_status);
32 static gs_memory_proc_free_all(gs_locked_free_all);
33 static gs_memory_proc_consolidate_free(gs_locked_consolidate_free);
34
35 /* Object memory procedures */
36 static gs_memory_proc_alloc_bytes(gs_locked_alloc_bytes);
37 static gs_memory_proc_alloc_struct(gs_locked_alloc_struct);
38 static gs_memory_proc_alloc_struct(gs_locked_alloc_struct_immovable);
39 static gs_memory_proc_alloc_byte_array(gs_locked_alloc_byte_array);
40 static gs_memory_proc_alloc_byte_array(gs_locked_alloc_byte_array_immovable);
41 static gs_memory_proc_alloc_struct_array(gs_locked_alloc_struct_array);
42 static gs_memory_proc_alloc_struct_array(gs_locked_alloc_struct_array_immovable);
43 static gs_memory_proc_object_size(gs_locked_object_size);
44 static gs_memory_proc_object_type(gs_locked_object_type);
45 static gs_memory_proc_alloc_string(gs_locked_alloc_string);
46 static gs_memory_proc_alloc_string(gs_locked_alloc_string_immovable);
47 static gs_memory_proc_resize_string(gs_locked_resize_string);
48 static gs_memory_proc_free_string(gs_locked_free_string);
49 static gs_memory_proc_register_root(gs_locked_register_root);
50 static gs_memory_proc_unregister_root(gs_locked_unregister_root);
51 static gs_memory_proc_enable_free(gs_locked_enable_free);
52 static const gs_memory_procs_t locked_procs =
53 {
54 /* Raw memory procedures */
55 gs_locked_alloc_bytes_immovable,
56 gs_locked_resize_object,
57 gs_locked_free_object,
58 gs_locked_stable,
59 gs_locked_status,
60 gs_locked_free_all,
61 gs_locked_consolidate_free,
62 /* Object memory procedures */
63 gs_locked_alloc_bytes,
64 gs_locked_alloc_struct,
65 gs_locked_alloc_struct_immovable,
66 gs_locked_alloc_byte_array,
67 gs_locked_alloc_byte_array_immovable,
68 gs_locked_alloc_struct_array,
69 gs_locked_alloc_struct_array_immovable,
70 gs_locked_object_size,
71 gs_locked_object_type,
72 gs_locked_alloc_string,
73 gs_locked_alloc_string_immovable,
74 gs_locked_resize_string,
75 gs_locked_free_string,
76 gs_locked_register_root,
77 gs_locked_unregister_root,
78 gs_locked_enable_free
79 };
80
81 /* ---------- Public constructors/destructors ---------- */
82
83 /* Initialize a gs_memory_locked_t */
84 int /* -ve error code or 0 */
gs_memory_locked_init(gs_memory_locked_t * lmem,gs_memory_t * target)85 gs_memory_locked_init(
86 gs_memory_locked_t * lmem, /* allocator to init */
87 gs_memory_t * target /* allocator to monitor lock */
88 )
89 {
90 lmem->stable_memory = 0;
91 lmem->procs = locked_procs;
92 lmem->target = target;
93 lmem->gs_lib_ctx = target->gs_lib_ctx;
94 lmem->non_gc_memory = (gs_memory_t *)lmem;
95
96 /* Allocate a monitor to serialize access to structures within */
97 lmem->monitor = gx_monitor_alloc(target);
98 return (lmem->monitor ? 0 : gs_note_error(gs_error_VMerror));
99 }
100
101 /* Release a locked memory manager. */
102 /* Note that this has no effect on the target. */
103 void
gs_memory_locked_release(gs_memory_locked_t * lmem)104 gs_memory_locked_release(gs_memory_locked_t *lmem)
105 {
106 gs_memory_free_all((gs_memory_t *)lmem, FREE_ALL_STRUCTURES,
107 "gs_memory_locked_release");
108 gx_monitor_free(lmem->monitor);
109 }
110
111 /* ---------- Accessors ------------- */
112
113 /* Retrieve this allocator's target */
114 gs_memory_t *
gs_memory_locked_target(const gs_memory_locked_t * lmem)115 gs_memory_locked_target(const gs_memory_locked_t *lmem)
116 {
117 return lmem->target;
118 }
119
120 /* -------- Private members just wrap a monitor around a gs_memory_heap --- */
121
122 /*
123 * Contrary to our usual practice, we don't use BEGIN/END here, because
124 * that causes some compilers to give bogus error messages.
125 */
126
127 #define DO_MONITORED(call_target)\
128 gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;\
129 \
130 gx_monitor_enter(lmem->monitor);\
131 call_target;\
132 gx_monitor_leave(lmem->monitor)
133
134 #define RETURN_MONITORED(result_type, call_target)\
135 gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;\
136 result_type temp;\
137 \
138 gx_monitor_enter(lmem->monitor);\
139 temp = call_target;\
140 gx_monitor_leave(lmem->monitor);\
141 return temp
142
143 /* Procedures */
144 static void
gs_locked_free_all(gs_memory_t * mem,uint free_mask,client_name_t cname)145 gs_locked_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname)
146 {
147 gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
148 gs_memory_t * const target = lmem->target;
149
150 /* Only free the structures and the allocator itself. */
151 if (mem->stable_memory) {
152 if (mem->stable_memory != mem)
153 gs_memory_free_all(mem->stable_memory, free_mask, cname);
154 if (free_mask & FREE_ALL_ALLOCATOR)
155 mem->stable_memory = 0;
156 }
157 if (free_mask & FREE_ALL_STRUCTURES) {
158 /*
159 * Check for monitor == 0, in case this is called after a
160 * failure during initialization.
161 */
162 if (lmem->monitor)
163 gx_monitor_free(lmem->monitor);
164 lmem->monitor = 0;
165 lmem->target = 0;
166 }
167 if (free_mask & FREE_ALL_ALLOCATOR)
168 gs_free_object(target, lmem, cname);
169 }
170 static void
gs_locked_consolidate_free(gs_memory_t * mem)171 gs_locked_consolidate_free(gs_memory_t * mem)
172 {
173 DO_MONITORED(
174 (*lmem->target->procs.consolidate_free)(lmem->target)
175 );
176 }
177 static byte *
gs_locked_alloc_bytes(gs_memory_t * mem,uint size,client_name_t cname)178 gs_locked_alloc_bytes(gs_memory_t * mem, uint size, client_name_t cname)
179 {
180 RETURN_MONITORED(
181 byte *,
182 (*lmem->target->procs.alloc_bytes)
183 (lmem->target, size, cname)
184 );
185 }
186 static byte *
gs_locked_alloc_bytes_immovable(gs_memory_t * mem,uint size,client_name_t cname)187 gs_locked_alloc_bytes_immovable(gs_memory_t * mem, uint size,
188 client_name_t cname)
189 {
190 RETURN_MONITORED(
191 byte *,
192 (*lmem->target->procs.alloc_bytes_immovable)
193 (lmem->target, size, cname)
194 );
195 }
196 static void *
gs_locked_alloc_struct(gs_memory_t * mem,gs_memory_type_ptr_t pstype,client_name_t cname)197 gs_locked_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
198 client_name_t cname)
199 {
200 RETURN_MONITORED(
201 void *,
202 (*lmem->target->procs.alloc_struct)
203 (lmem->target, pstype, cname)
204 );
205 }
206 static void *
gs_locked_alloc_struct_immovable(gs_memory_t * mem,gs_memory_type_ptr_t pstype,client_name_t cname)207 gs_locked_alloc_struct_immovable(gs_memory_t * mem,
208 gs_memory_type_ptr_t pstype, client_name_t cname)
209 {
210 RETURN_MONITORED(
211 void *,
212 (*lmem->target->procs.alloc_struct_immovable)
213 (lmem->target, pstype, cname)
214 );
215 }
216 static byte *
gs_locked_alloc_byte_array(gs_memory_t * mem,uint num_elements,uint elt_size,client_name_t cname)217 gs_locked_alloc_byte_array(gs_memory_t * mem, uint num_elements, uint elt_size,
218 client_name_t cname)
219 {
220 RETURN_MONITORED(
221 byte *,
222 (*lmem->target->procs.alloc_byte_array)
223 (lmem->target, num_elements, elt_size, cname)
224 );
225 }
226 static byte *
gs_locked_alloc_byte_array_immovable(gs_memory_t * mem,uint num_elements,uint elt_size,client_name_t cname)227 gs_locked_alloc_byte_array_immovable(gs_memory_t * mem, uint num_elements,
228 uint elt_size, client_name_t cname)
229 {
230 RETURN_MONITORED(
231 byte *,
232 (*lmem->target->procs.alloc_byte_array_immovable)
233 (lmem->target, num_elements, elt_size, cname)
234 );
235 }
236 static void *
gs_locked_alloc_struct_array(gs_memory_t * mem,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)237 gs_locked_alloc_struct_array(gs_memory_t * mem, uint num_elements,
238 gs_memory_type_ptr_t pstype, client_name_t cname)
239 {
240 RETURN_MONITORED(
241 void *,
242 (*lmem->target->procs.alloc_struct_array)
243 (lmem->target, num_elements, pstype, cname)
244 );
245 }
246 static void *
gs_locked_alloc_struct_array_immovable(gs_memory_t * mem,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)247 gs_locked_alloc_struct_array_immovable(gs_memory_t * mem, uint num_elements,
248 gs_memory_type_ptr_t pstype, client_name_t cname)
249 {
250 RETURN_MONITORED(
251 void *,
252 (*lmem->target->procs.alloc_struct_array_immovable)
253 (lmem->target, num_elements, pstype, cname)
254 );
255 }
256 static void *
gs_locked_resize_object(gs_memory_t * mem,void * obj,uint new_num_elements,client_name_t cname)257 gs_locked_resize_object(gs_memory_t * mem, void *obj, uint new_num_elements,
258 client_name_t cname)
259 {
260 RETURN_MONITORED(
261 void *,
262 (*lmem->target->procs.resize_object)
263 (lmem->target, obj, new_num_elements, cname)
264 );
265 }
266 static uint
gs_locked_object_size(gs_memory_t * mem,const void * ptr)267 gs_locked_object_size(gs_memory_t * mem, const void *ptr)
268 {
269 RETURN_MONITORED(
270 uint,
271 (*lmem->target->procs.object_size)
272 (lmem->target, ptr)
273 );
274 }
275 static gs_memory_type_ptr_t
gs_locked_object_type(const gs_memory_t * mem,const void * ptr)276 gs_locked_object_type(const gs_memory_t * mem, const void *ptr)
277 {
278 RETURN_MONITORED(
279 gs_memory_type_ptr_t,
280 (*lmem->target->procs.object_type)
281 (lmem->target, ptr)
282 );
283 }
284 static void
gs_locked_free_object(gs_memory_t * mem,void * ptr,client_name_t cname)285 gs_locked_free_object(gs_memory_t * mem, void *ptr, client_name_t cname)
286 {
287 DO_MONITORED(
288 (*lmem->target->procs.free_object)
289 (lmem->target, ptr, cname)
290 );
291 }
292 static byte *
gs_locked_alloc_string(gs_memory_t * mem,uint nbytes,client_name_t cname)293 gs_locked_alloc_string(gs_memory_t * mem, uint nbytes, client_name_t cname)
294 {
295 RETURN_MONITORED(
296 byte *,
297 (*lmem->target->procs.alloc_string)
298 (lmem->target, nbytes, cname)
299 );
300 }
301 static byte *
gs_locked_alloc_string_immovable(gs_memory_t * mem,uint nbytes,client_name_t cname)302 gs_locked_alloc_string_immovable(gs_memory_t * mem, uint nbytes,
303 client_name_t cname)
304 {
305 RETURN_MONITORED(
306 byte *,
307 (*lmem->target->procs.alloc_string_immovable)
308 (lmem->target, nbytes, cname)
309 );
310 }
311 static byte *
gs_locked_resize_string(gs_memory_t * mem,byte * data,uint old_num,uint new_num,client_name_t cname)312 gs_locked_resize_string(gs_memory_t * mem, byte * data, uint old_num,
313 uint new_num,
314 client_name_t cname)
315 {
316 RETURN_MONITORED(
317 byte *,
318 (*lmem->target->procs.resize_string)
319 (lmem->target, data, old_num, new_num, cname)
320 );
321 }
322 static void
gs_locked_free_string(gs_memory_t * mem,byte * data,uint nbytes,client_name_t cname)323 gs_locked_free_string(gs_memory_t * mem, byte * data, uint nbytes,
324 client_name_t cname)
325 {
326 DO_MONITORED(
327 (*lmem->target->procs.free_string)
328 (lmem->target, data, nbytes, cname)
329 );
330 }
331 static int
gs_locked_register_root(gs_memory_t * mem,gs_gc_root_t * rp,gs_ptr_type_t ptype,void ** up,client_name_t cname)332 gs_locked_register_root(gs_memory_t * mem, gs_gc_root_t * rp,
333 gs_ptr_type_t ptype, void **up, client_name_t cname)
334 {
335 RETURN_MONITORED(
336 int,
337 (*lmem->target->procs.register_root)
338 (lmem->target, rp, ptype, up, cname)
339 );
340 }
341 static void
gs_locked_unregister_root(gs_memory_t * mem,gs_gc_root_t * rp,client_name_t cname)342 gs_locked_unregister_root(gs_memory_t * mem, gs_gc_root_t * rp,
343 client_name_t cname)
344 {
345 DO_MONITORED(
346 (*lmem->target->procs.unregister_root)
347 (lmem->target, rp, cname)
348 );
349 }
350 static gs_memory_t *
gs_locked_stable(gs_memory_t * mem)351 gs_locked_stable(gs_memory_t * mem)
352 {
353 if (!mem->stable_memory) {
354 gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
355 gs_memory_t *stable;
356
357 gx_monitor_enter(lmem->monitor);
358 stable = gs_memory_stable(lmem->target);
359 if (stable == lmem->target)
360 mem->stable_memory = mem;
361 else {
362 gs_memory_locked_t *locked_stable = (gs_memory_locked_t *)
363 gs_alloc_bytes(stable, sizeof(*lmem), "gs_locked_stable");
364
365 if (locked_stable) {
366 int code = gs_memory_locked_init(locked_stable, stable);
367
368 if (code < 0)
369 gs_free_object(stable, locked_stable, "gs_locked_stable");
370 else
371 mem->stable_memory = (gs_memory_t *)locked_stable;
372 }
373 }
374 gx_monitor_leave(lmem->monitor);
375 }
376 return mem->stable_memory;
377 }
378 static void
gs_locked_status(gs_memory_t * mem,gs_memory_status_t * pstat)379 gs_locked_status(gs_memory_t * mem, gs_memory_status_t * pstat)
380 {
381 DO_MONITORED(
382 (*lmem->target->procs.status)(lmem->target, pstat)
383 );
384 }
385 static void
gs_locked_enable_free(gs_memory_t * mem,bool enable)386 gs_locked_enable_free(gs_memory_t * mem, bool enable)
387 {
388 DO_MONITORED(
389 (*lmem->target->procs.enable_free)(lmem->target, enable)
390 );
391 }
392