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