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