xref: /plan9/sys/src/cmd/gs/src/gsmemlok.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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