xref: /plan9/sys/src/cmd/gs/src/gsmemret.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1999 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: gsmemret.c,v 1.5 2004/08/04 19:36:12 stefan Exp $ */
18 /* Retrying memory allocator */
19 
20 #include "gx.h"
21 #include "gsmemret.h"
22 #include "gserrors.h"
23 
24 /* Raw memory procedures */
25 private gs_memory_proc_alloc_bytes(gs_retrying_alloc_bytes_immovable);
26 private gs_memory_proc_resize_object(gs_retrying_resize_object);
27 private gs_memory_proc_free_object(gs_forward_free_object);
28 private gs_memory_proc_stable(gs_retrying_stable);
29 private gs_memory_proc_status(gs_forward_status);
30 private gs_memory_proc_free_all(gs_forward_free_all);
31 private gs_memory_proc_consolidate_free(gs_forward_consolidate_free);
32 
33 /* Object memory procedures */
34 private gs_memory_proc_alloc_bytes(gs_retrying_alloc_bytes);
35 private gs_memory_proc_alloc_struct(gs_retrying_alloc_struct);
36 private gs_memory_proc_alloc_struct(gs_retrying_alloc_struct_immovable);
37 private gs_memory_proc_alloc_byte_array(gs_retrying_alloc_byte_array);
38 private gs_memory_proc_alloc_byte_array(gs_retrying_alloc_byte_array_immovable);
39 private gs_memory_proc_alloc_struct_array(gs_retrying_alloc_struct_array);
40 private gs_memory_proc_alloc_struct_array(gs_retrying_alloc_struct_array_immovable);
41 private gs_memory_proc_object_size(gs_forward_object_size);
42 private gs_memory_proc_object_type(gs_forward_object_type);
43 private gs_memory_proc_alloc_string(gs_retrying_alloc_string);
44 private gs_memory_proc_alloc_string(gs_retrying_alloc_string_immovable);
45 private gs_memory_proc_resize_string(gs_retrying_resize_string);
46 private gs_memory_proc_free_string(gs_forward_free_string);
47 private gs_memory_proc_register_root(gs_retrying_register_root);
48 private gs_memory_proc_unregister_root(gs_forward_unregister_root);
49 private gs_memory_proc_enable_free(gs_forward_enable_free);
50 private const gs_memory_procs_t retrying_procs = {
51     /* Raw memory procedures */
52     gs_retrying_alloc_bytes_immovable,
53     gs_retrying_resize_object,
54     gs_forward_free_object,
55     gs_retrying_stable,
56     gs_forward_status,
57     gs_forward_free_all,
58     gs_forward_consolidate_free,
59     /* Object memory procedures */
60     gs_retrying_alloc_bytes,
61     gs_retrying_alloc_struct,
62     gs_retrying_alloc_struct_immovable,
63     gs_retrying_alloc_byte_array,
64     gs_retrying_alloc_byte_array_immovable,
65     gs_retrying_alloc_struct_array,
66     gs_retrying_alloc_struct_array_immovable,
67     gs_forward_object_size,
68     gs_forward_object_type,
69     gs_retrying_alloc_string,
70     gs_retrying_alloc_string_immovable,
71     gs_retrying_resize_string,
72     gs_forward_free_string,
73     gs_retrying_register_root,
74     gs_forward_unregister_root,
75     gs_forward_enable_free
76 };
77 
78 /* Define a vacuous recovery procedure. */
79 private gs_memory_recover_status_t
no_recover_proc(gs_memory_retrying_t * rmem,void * proc_data)80 no_recover_proc(gs_memory_retrying_t *rmem, void *proc_data)
81 {
82     return RECOVER_STATUS_NO_RETRY;
83 }
84 
85 /* ---------- Public constructors/destructors ---------- */
86 
87 /* Initialize a gs_memory_retrying_t */
88 int				/* -ve error code or 0 */
gs_memory_retrying_init(gs_memory_retrying_t * rmem,gs_memory_t * target)89 gs_memory_retrying_init(
90 		      gs_memory_retrying_t * rmem,	/* allocator to init */
91 		      gs_memory_t * target	/* allocator to wrap */
92 )
93 {
94     rmem->stable_memory = 0;
95     rmem->procs = retrying_procs;
96     rmem->target = target;
97     rmem->gs_lib_ctx = target->gs_lib_ctx;
98     rmem->non_gc_memory = (gs_memory_t *)rmem;
99     gs_memory_retrying_set_recover(rmem, no_recover_proc, NULL);
100     return 0;
101 }
102 
103 /* Set the recovery closure of a retrying memory manager. */
104 void
gs_memory_retrying_set_recover(gs_memory_retrying_t * rmem,gs_memory_recover_proc_t recover_proc,void * recover_proc_data)105 gs_memory_retrying_set_recover(gs_memory_retrying_t *rmem,
106 			       gs_memory_recover_proc_t recover_proc,
107 			       void *recover_proc_data)
108 {
109     rmem->recover_proc = recover_proc;
110     rmem->recover_proc_data = recover_proc_data;
111 }
112 
113 /* Release a retrying memory manager. */
114 /* Note that this has no effect on the target. */
115 void
gs_memory_retrying_release(gs_memory_retrying_t * rmem)116 gs_memory_retrying_release(gs_memory_retrying_t *rmem)
117 {
118     gs_memory_free_all((gs_memory_t *)rmem, FREE_ALL_STRUCTURES,
119 		       "gs_memory_retrying_release");
120 }
121 
122 /* ---------- Accessors ------------- */
123 
124 /* Retrieve this allocator's target */
125 gs_memory_t *
gs_memory_retrying_target(const gs_memory_retrying_t * rmem)126 gs_memory_retrying_target(const gs_memory_retrying_t *rmem)
127 {
128     return rmem->target;
129 }
130 
131 /* -------- Private members just wrap retrying around a gs_memory --- */
132 
133 /*
134  * Contrary to our usual practice, we don't use BEGIN/END here, because
135  * that causes some compilers to give bogus error messages.
136  */
137 
138 #define DO_FORWARD(call_target)\
139 	gs_memory_retrying_t * const rmem = (gs_memory_retrying_t *)mem;\
140 	gs_memory_t *const target = rmem->target;\
141 \
142 	call_target
143 
144 #define RETURN_RETRYING(result_type, call_target)\
145 	gs_memory_retrying_t * const rmem = (gs_memory_retrying_t *)mem;\
146 	gs_memory_t *const target = rmem->target;\
147 	result_type temp;\
148 	gs_memory_recover_status_t retry = RECOVER_STATUS_RETRY_OK;\
149 \
150 	for (;;) {\
151 	    temp = call_target;\
152 	    if (temp != 0 || retry != RECOVER_STATUS_RETRY_OK)\
153 		break;\
154 	    retry = rmem->recover_proc(rmem, rmem->recover_proc_data);\
155 	}\
156 	return temp
157 
158 /* Procedures */
159 private void
gs_forward_free_all(gs_memory_t * mem,uint free_mask,client_name_t cname)160 gs_forward_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname)
161 {
162     gs_memory_retrying_t * const rmem = (gs_memory_retrying_t *)mem;
163     gs_memory_t * const target = rmem->target;
164 
165     /* Only free the structures and the allocator itself. */
166     rmem->target = 0;
167     if (free_mask & FREE_ALL_ALLOCATOR)
168 	gs_free_object(target, rmem, cname);
169 }
170 private void
gs_forward_consolidate_free(gs_memory_t * mem)171 gs_forward_consolidate_free(gs_memory_t * mem)
172 {
173     DO_FORWARD(target->procs.consolidate_free(target));
174 }
175 private byte *
gs_retrying_alloc_bytes(gs_memory_t * mem,uint size,client_name_t cname)176 gs_retrying_alloc_bytes(gs_memory_t * mem, uint size, client_name_t cname)
177 {
178     RETURN_RETRYING(
179 		    byte *,
180 		    target->procs.alloc_bytes(target, size, cname)
181 		    );
182 }
183 private byte *
gs_retrying_alloc_bytes_immovable(gs_memory_t * mem,uint size,client_name_t cname)184 gs_retrying_alloc_bytes_immovable(gs_memory_t * mem, uint size,
185 				client_name_t cname)
186 {
187     RETURN_RETRYING(
188 		    byte *,
189 		    target->procs.alloc_bytes_immovable(target, size, cname)
190 		    );
191 }
192 private void *
gs_retrying_alloc_struct(gs_memory_t * mem,gs_memory_type_ptr_t pstype,client_name_t cname)193 gs_retrying_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
194 		       client_name_t cname)
195 {
196     RETURN_RETRYING(
197 		    void *,
198 		    target->procs.alloc_struct(target, pstype, cname)
199 		    );
200 }
201 private void *
gs_retrying_alloc_struct_immovable(gs_memory_t * mem,gs_memory_type_ptr_t pstype,client_name_t cname)202 gs_retrying_alloc_struct_immovable(gs_memory_t * mem,
203 			   gs_memory_type_ptr_t pstype, client_name_t cname)
204 {
205     RETURN_RETRYING(
206 		    void *,
207 		    target->procs.alloc_struct_immovable(target, pstype, cname)
208 		    );
209 }
210 private byte *
gs_retrying_alloc_byte_array(gs_memory_t * mem,uint num_elements,uint elt_size,client_name_t cname)211 gs_retrying_alloc_byte_array(gs_memory_t * mem, uint num_elements, uint elt_size,
212 			   client_name_t cname)
213 {
214     RETURN_RETRYING(
215 		    byte *,
216 		    target->procs.alloc_byte_array(target, num_elements,
217 						   elt_size, cname)
218 		    );
219 }
220 private byte *
gs_retrying_alloc_byte_array_immovable(gs_memory_t * mem,uint num_elements,uint elt_size,client_name_t cname)221 gs_retrying_alloc_byte_array_immovable(gs_memory_t * mem, uint num_elements,
222 				     uint elt_size, client_name_t cname)
223 {
224     RETURN_RETRYING(
225 		    byte *,
226 		    target->procs.alloc_byte_array_immovable(target,
227 							num_elements, elt_size,
228 							cname)
229 		    );
230 }
231 private void *
gs_retrying_alloc_struct_array(gs_memory_t * mem,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)232 gs_retrying_alloc_struct_array(gs_memory_t * mem, uint num_elements,
233 			   gs_memory_type_ptr_t pstype, client_name_t cname)
234 {
235     RETURN_RETRYING(
236 		    void *,
237 		    target->procs.alloc_struct_array(target, num_elements,
238 						     pstype, cname)
239 		    );
240 }
241 private void *
gs_retrying_alloc_struct_array_immovable(gs_memory_t * mem,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)242 gs_retrying_alloc_struct_array_immovable(gs_memory_t * mem, uint num_elements,
243 			   gs_memory_type_ptr_t pstype, client_name_t cname)
244 {
245     RETURN_RETRYING(
246 		    void *,
247 		    target->procs.alloc_struct_array_immovable(target,
248 							num_elements, pstype,
249 						        cname)
250 		    );
251 }
252 private void *
gs_retrying_resize_object(gs_memory_t * mem,void * obj,uint new_num_elements,client_name_t cname)253 gs_retrying_resize_object(gs_memory_t * mem, void *obj, uint new_num_elements,
254 			client_name_t cname)
255 {
256     RETURN_RETRYING(
257 		    void *,
258 		    target->procs.resize_object(target, obj, new_num_elements,
259 						cname)
260 		    );
261 }
262 private uint
gs_forward_object_size(gs_memory_t * mem,const void * ptr)263 gs_forward_object_size(gs_memory_t * mem, const void *ptr)
264 {
265     DO_FORWARD(return target->procs.object_size(target, ptr));
266 }
267 private gs_memory_type_ptr_t
gs_forward_object_type(gs_memory_t * mem,const void * ptr)268 gs_forward_object_type(gs_memory_t * mem, const void *ptr)
269 {
270     DO_FORWARD(return target->procs.object_type(target, ptr));
271 }
272 private void
gs_forward_free_object(gs_memory_t * mem,void * ptr,client_name_t cname)273 gs_forward_free_object(gs_memory_t * mem, void *ptr, client_name_t cname)
274 {
275     DO_FORWARD(target->procs.free_object(target, ptr, cname));
276 }
277 private byte *
gs_retrying_alloc_string(gs_memory_t * mem,uint nbytes,client_name_t cname)278 gs_retrying_alloc_string(gs_memory_t * mem, uint nbytes, client_name_t cname)
279 {
280     RETURN_RETRYING(
281 		    byte *,
282 		    target->procs.alloc_string(target, nbytes, cname)
283 		    );
284 }
285 private byte *
gs_retrying_alloc_string_immovable(gs_memory_t * mem,uint nbytes,client_name_t cname)286 gs_retrying_alloc_string_immovable(gs_memory_t * mem, uint nbytes,
287 				 client_name_t cname)
288 {
289     RETURN_RETRYING(
290 		    byte *,
291 		    target->procs.alloc_string_immovable(target, nbytes, cname)
292 		    );
293 }
294 private byte *
gs_retrying_resize_string(gs_memory_t * mem,byte * data,uint old_num,uint new_num,client_name_t cname)295 gs_retrying_resize_string(gs_memory_t * mem, byte * data, uint old_num,
296 			uint new_num,
297 			client_name_t cname)
298 {
299     RETURN_RETRYING(
300 		    byte *,
301 		    target->procs.resize_string(target, data, old_num, new_num,
302 						cname)
303 		    );
304 }
305 private void
gs_forward_free_string(gs_memory_t * mem,byte * data,uint nbytes,client_name_t cname)306 gs_forward_free_string(gs_memory_t * mem, byte * data, uint nbytes,
307 		      client_name_t cname)
308 {
309     DO_FORWARD(target->procs.free_string(target, data, nbytes, cname));
310 }
311 private int
gs_retrying_register_root(gs_memory_t * mem,gs_gc_root_t * rp,gs_ptr_type_t ptype,void ** up,client_name_t cname)312 gs_retrying_register_root(gs_memory_t * mem, gs_gc_root_t * rp,
313 			gs_ptr_type_t ptype, void **up, client_name_t cname)
314 {
315     RETURN_RETRYING(
316 		    int,
317 		    target->procs.register_root(target, rp, ptype, up, cname)
318 		    );
319 }
320 private void
gs_forward_unregister_root(gs_memory_t * mem,gs_gc_root_t * rp,client_name_t cname)321 gs_forward_unregister_root(gs_memory_t * mem, gs_gc_root_t * rp,
322 			  client_name_t cname)
323 {
324     DO_FORWARD(target->procs.unregister_root(target, rp, cname));
325 }
326 private gs_memory_t *
gs_retrying_stable(gs_memory_t * mem)327 gs_retrying_stable(gs_memory_t * mem)
328 {
329     if (!mem->stable_memory) {
330 	gs_memory_retrying_t * const rmem = (gs_memory_retrying_t *)mem;
331 	gs_memory_t *stable = gs_memory_stable(rmem->target);
332 
333 	if (stable == rmem->target)
334 	    mem->stable_memory = mem;
335 	else {
336 	    gs_memory_retrying_t *retrying_stable = (gs_memory_retrying_t *)
337 		gs_alloc_bytes(stable, sizeof(*rmem), "gs_retrying_stable");
338 
339 	    if (retrying_stable) {
340 		int code = gs_memory_retrying_init(retrying_stable, stable);
341 
342 		if (code < 0)
343 		    gs_free_object(stable, retrying_stable, "gs_retrying_stable");
344 		else
345 		    mem->stable_memory = (gs_memory_t *)retrying_stable;
346 	    }
347 	}
348     }
349     return mem->stable_memory;
350 }
351 private void
gs_forward_status(gs_memory_t * mem,gs_memory_status_t * pstat)352 gs_forward_status(gs_memory_t * mem, gs_memory_status_t * pstat)
353 {
354     DO_FORWARD(target->procs.status(target, pstat));
355 }
356 private void
gs_forward_enable_free(gs_memory_t * mem,bool enable)357 gs_forward_enable_free(gs_memory_t * mem, bool enable)
358 {
359     DO_FORWARD(target->procs.enable_free(target, enable));
360 }
361