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