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