1 /* Copyright (C) 2001-2012 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,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Monitor-locked heap memory allocator */
18 
19 /* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
20 /* Revised 8/6/98 by L. Peter Deutsch (ghost@aladdin.com) for changes */
21 /*   in memory manager API */
22 /* Edited 3/23/1999 by L. Peter Deutsch to remove compiler warnings. */
23 
24 #include "gx.h"
25 #include "gsmemlok.h"
26 #include "gserrors.h"
27 
28 /* Raw memory procedures */
29 static gs_memory_proc_alloc_bytes(gs_locked_alloc_bytes_immovable);
30 static gs_memory_proc_resize_object(gs_locked_resize_object);
31 static gs_memory_proc_free_object(gs_locked_free_object);
32 static gs_memory_proc_stable(gs_locked_stable);
33 static gs_memory_proc_status(gs_locked_status);
34 static gs_memory_proc_free_all(gs_locked_free_all);
35 static gs_memory_proc_consolidate_free(gs_locked_consolidate_free);
36 
37 /* Object memory procedures */
38 static gs_memory_proc_alloc_bytes(gs_locked_alloc_bytes);
39 static gs_memory_proc_alloc_struct(gs_locked_alloc_struct);
40 static gs_memory_proc_alloc_struct(gs_locked_alloc_struct_immovable);
41 static gs_memory_proc_alloc_byte_array(gs_locked_alloc_byte_array);
42 static gs_memory_proc_alloc_byte_array(gs_locked_alloc_byte_array_immovable);
43 static gs_memory_proc_alloc_struct_array(gs_locked_alloc_struct_array);
44 static gs_memory_proc_alloc_struct_array(gs_locked_alloc_struct_array_immovable);
45 static gs_memory_proc_object_size(gs_locked_object_size);
46 static gs_memory_proc_object_type(gs_locked_object_type);
47 static gs_memory_proc_alloc_string(gs_locked_alloc_string);
48 static gs_memory_proc_alloc_string(gs_locked_alloc_string_immovable);
49 static gs_memory_proc_resize_string(gs_locked_resize_string);
50 static gs_memory_proc_free_string(gs_locked_free_string);
51 static gs_memory_proc_register_root(gs_locked_register_root);
52 static gs_memory_proc_unregister_root(gs_locked_unregister_root);
53 static gs_memory_proc_enable_free(gs_locked_enable_free);
54 static const gs_memory_procs_t locked_procs =
55 {
56     /* Raw memory procedures */
57     gs_locked_alloc_bytes_immovable,
58     gs_locked_resize_object,
59     gs_locked_free_object,
60     gs_locked_stable,
61     gs_locked_status,
62     gs_locked_free_all,
63     gs_locked_consolidate_free,
64     /* Object memory procedures */
65     gs_locked_alloc_bytes,
66     gs_locked_alloc_struct,
67     gs_locked_alloc_struct_immovable,
68     gs_locked_alloc_byte_array,
69     gs_locked_alloc_byte_array_immovable,
70     gs_locked_alloc_struct_array,
71     gs_locked_alloc_struct_array_immovable,
72     gs_locked_object_size,
73     gs_locked_object_type,
74     gs_locked_alloc_string,
75     gs_locked_alloc_string_immovable,
76     gs_locked_resize_string,
77     gs_locked_free_string,
78     gs_locked_register_root,
79     gs_locked_unregister_root,
80     gs_locked_enable_free
81 };
82 
83 /* ---------- Public constructors/destructors ---------- */
84 
85 /* Initialize a gs_memory_locked_t */
86 int				/* -ve error code or 0 */
gs_memory_locked_init(gs_memory_locked_t * lmem,gs_memory_t * target)87 gs_memory_locked_init(
88                       gs_memory_locked_t * lmem,	/* allocator to init */
89                       gs_memory_t * target	/* allocator to monitor lock */
90 )
91 {
92     lmem->stable_memory = 0;
93     lmem->procs = locked_procs;
94     lmem->target = target;
95     lmem->gs_lib_ctx = target->gs_lib_ctx;
96     lmem->non_gc_memory = (gs_memory_t *)lmem;		/* WRONG: THIS IS QUESTIONABLE since this will not */
97                                                         /* be non_gc_memory if the target was a GC memory  */
98     lmem->thread_safe_memory = (gs_memory_t *)lmem;	/* this allocator is thread safe */
99 
100     /* Allocate a monitor to serialize access to structures within */
101     lmem->monitor = gx_monitor_alloc(target);
102     return (lmem->monitor ? 0 : gs_note_error(gs_error_VMerror));
103 }
104 
105 /* Release a locked memory manager. */
106 /* Note that this has no effect on the target. */
107 void
gs_memory_locked_release(gs_memory_locked_t * lmem)108 gs_memory_locked_release(gs_memory_locked_t *lmem)
109 {
110     gs_memory_free_all((gs_memory_t *)lmem, FREE_ALL_STRUCTURES,
111                        "gs_memory_locked_release");
112     gx_monitor_free(lmem->monitor);
113 }
114 
115 /* ---------- Accessors ------------- */
116 
117 /* Retrieve this allocator's target */
118 gs_memory_t *
gs_memory_locked_target(const gs_memory_locked_t * lmem)119 gs_memory_locked_target(const gs_memory_locked_t *lmem)
120 {
121     return lmem->target;
122 }
123 
124 /* -------- Private members just wrap a monitor around a gs_memory_heap --- */
125 
126 /*
127  * Contrary to our usual practice, we don't use BEGIN/END here, because
128  * that causes some compilers to give bogus error messages.
129  */
130 
131 #define DO_MONITORED(call_target)\
132         gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;\
133 \
134         gx_monitor_enter(lmem->monitor);\
135         call_target;\
136         gx_monitor_leave(lmem->monitor)
137 
138 #define RETURN_MONITORED(result_type, call_target)\
139         gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;\
140         result_type temp;\
141 \
142         gx_monitor_enter(lmem->monitor);\
143         temp = call_target;\
144         gx_monitor_leave(lmem->monitor);\
145         return temp
146 
147 /* Procedures */
148 static void
gs_locked_free_all(gs_memory_t * mem,uint free_mask,client_name_t cname)149 gs_locked_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname)
150 {
151     gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
152     gs_memory_t * const target = lmem->target;
153 
154     /* Only free the structures and the allocator itself. */
155     if (mem->stable_memory) {
156         if (mem->stable_memory != mem)
157             gs_memory_free_all(mem->stable_memory, free_mask, cname);
158         if (free_mask & FREE_ALL_ALLOCATOR)
159             mem->stable_memory = 0;
160     }
161     if (free_mask & FREE_ALL_STRUCTURES) {
162         /*
163          * Check for monitor == 0, in case this is called after a
164          * failure during initialization.
165          */
166         if (lmem->monitor)
167             gx_monitor_free(lmem->monitor);
168         lmem->monitor = 0;
169         lmem->target = 0;
170     }
171     if (free_mask & FREE_ALL_ALLOCATOR)
172         gs_free_object(target, lmem, cname);
173 }
174 static void
gs_locked_consolidate_free(gs_memory_t * mem)175 gs_locked_consolidate_free(gs_memory_t * mem)
176 {
177     DO_MONITORED(
178                  (*lmem->target->procs.consolidate_free)(lmem->target)
179                  );
180 }
181 static byte *
gs_locked_alloc_bytes(gs_memory_t * mem,uint size,client_name_t cname)182 gs_locked_alloc_bytes(gs_memory_t * mem, uint size, client_name_t cname)
183 {
184     RETURN_MONITORED(
185                      byte *,
186                      (*lmem->target->procs.alloc_bytes)
187                        (lmem->target, size, cname)
188                      );
189 }
190 static byte *
gs_locked_alloc_bytes_immovable(gs_memory_t * mem,uint size,client_name_t cname)191 gs_locked_alloc_bytes_immovable(gs_memory_t * mem, uint size,
192                                 client_name_t cname)
193 {
194     RETURN_MONITORED(
195                      byte *,
196                      (*lmem->target->procs.alloc_bytes_immovable)
197                        (lmem->target, size, cname)
198                      );
199 }
200 static void *
gs_locked_alloc_struct(gs_memory_t * mem,gs_memory_type_ptr_t pstype,client_name_t cname)201 gs_locked_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
202                        client_name_t cname)
203 {
204     RETURN_MONITORED(
205                      void *,
206                      (*lmem->target->procs.alloc_struct)
207                        (lmem->target, pstype, cname)
208                      );
209 }
210 static void *
gs_locked_alloc_struct_immovable(gs_memory_t * mem,gs_memory_type_ptr_t pstype,client_name_t cname)211 gs_locked_alloc_struct_immovable(gs_memory_t * mem,
212                            gs_memory_type_ptr_t pstype, client_name_t cname)
213 {
214     RETURN_MONITORED(
215                      void *,
216                      (*lmem->target->procs.alloc_struct_immovable)
217                        (lmem->target, pstype, cname)
218                      );
219 }
220 static byte *
gs_locked_alloc_byte_array(gs_memory_t * mem,uint num_elements,uint elt_size,client_name_t cname)221 gs_locked_alloc_byte_array(gs_memory_t * mem, uint num_elements, uint elt_size,
222                            client_name_t cname)
223 {
224     RETURN_MONITORED(
225                      byte *,
226                      (*lmem->target->procs.alloc_byte_array)
227                        (lmem->target, num_elements, elt_size, cname)
228                      );
229 }
230 static byte *
gs_locked_alloc_byte_array_immovable(gs_memory_t * mem,uint num_elements,uint elt_size,client_name_t cname)231 gs_locked_alloc_byte_array_immovable(gs_memory_t * mem, uint num_elements,
232                                      uint elt_size, client_name_t cname)
233 {
234     RETURN_MONITORED(
235                      byte *,
236                      (*lmem->target->procs.alloc_byte_array_immovable)
237                        (lmem->target, num_elements, elt_size, cname)
238                      );
239 }
240 static void *
gs_locked_alloc_struct_array(gs_memory_t * mem,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)241 gs_locked_alloc_struct_array(gs_memory_t * mem, uint num_elements,
242                            gs_memory_type_ptr_t pstype, client_name_t cname)
243 {
244     RETURN_MONITORED(
245                      void *,
246                      (*lmem->target->procs.alloc_struct_array)
247                        (lmem->target, num_elements, pstype, cname)
248                      );
249 }
250 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)251 gs_locked_alloc_struct_array_immovable(gs_memory_t * mem, uint num_elements,
252                            gs_memory_type_ptr_t pstype, client_name_t cname)
253 {
254     RETURN_MONITORED(
255                      void *,
256                      (*lmem->target->procs.alloc_struct_array_immovable)
257                        (lmem->target, num_elements, pstype, cname)
258                      );
259 }
260 static void *
gs_locked_resize_object(gs_memory_t * mem,void * obj,uint new_num_elements,client_name_t cname)261 gs_locked_resize_object(gs_memory_t * mem, void *obj, uint new_num_elements,
262                         client_name_t cname)
263 {
264     RETURN_MONITORED(
265                      void *,
266                      (*lmem->target->procs.resize_object)
267                        (lmem->target, obj, new_num_elements, cname)
268                      );
269 }
270 static uint
gs_locked_object_size(gs_memory_t * mem,const void * ptr)271 gs_locked_object_size(gs_memory_t * mem, const void *ptr)
272 {
273     RETURN_MONITORED(
274                      uint,
275                      (*lmem->target->procs.object_size)
276                        (lmem->target, ptr)
277                      );
278 }
279 static gs_memory_type_ptr_t
gs_locked_object_type(const gs_memory_t * mem,const void * ptr)280 gs_locked_object_type(const gs_memory_t * mem, const void *ptr)
281 {
282     RETURN_MONITORED(
283                      gs_memory_type_ptr_t,
284                      (*lmem->target->procs.object_type)
285                        (lmem->target, ptr)
286                      );
287 }
288 static void
gs_locked_free_object(gs_memory_t * mem,void * ptr,client_name_t cname)289 gs_locked_free_object(gs_memory_t * mem, void *ptr, client_name_t cname)
290 {
291     DO_MONITORED(
292                  (*lmem->target->procs.free_object)
293                    (lmem->target, ptr, cname)
294                  );
295 }
296 static byte *
gs_locked_alloc_string(gs_memory_t * mem,uint nbytes,client_name_t cname)297 gs_locked_alloc_string(gs_memory_t * mem, uint nbytes, client_name_t cname)
298 {
299     RETURN_MONITORED(
300                      byte *,
301                      (*lmem->target->procs.alloc_string)
302                        (lmem->target, nbytes, cname)
303                      );
304 }
305 static byte *
gs_locked_alloc_string_immovable(gs_memory_t * mem,uint nbytes,client_name_t cname)306 gs_locked_alloc_string_immovable(gs_memory_t * mem, uint nbytes,
307                                  client_name_t cname)
308 {
309     RETURN_MONITORED(
310                      byte *,
311                      (*lmem->target->procs.alloc_string_immovable)
312                        (lmem->target, nbytes, cname)
313                      );
314 }
315 static byte *
gs_locked_resize_string(gs_memory_t * mem,byte * data,uint old_num,uint new_num,client_name_t cname)316 gs_locked_resize_string(gs_memory_t * mem, byte * data, uint old_num,
317                         uint new_num,
318                         client_name_t cname)
319 {
320     RETURN_MONITORED(
321                      byte *,
322                      (*lmem->target->procs.resize_string)
323                        (lmem->target, data, old_num, new_num, cname)
324                      );
325 }
326 static void
gs_locked_free_string(gs_memory_t * mem,byte * data,uint nbytes,client_name_t cname)327 gs_locked_free_string(gs_memory_t * mem, byte * data, uint nbytes,
328                       client_name_t cname)
329 {
330     DO_MONITORED(
331                  (*lmem->target->procs.free_string)
332                    (lmem->target, data, nbytes, cname)
333                  );
334 }
335 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)336 gs_locked_register_root(gs_memory_t * mem, gs_gc_root_t * rp,
337                         gs_ptr_type_t ptype, void **up, client_name_t cname)
338 {
339     RETURN_MONITORED(
340                      int,
341                      (*lmem->target->procs.register_root)
342                        (lmem->target, rp, ptype, up, cname)
343                      );
344 }
345 static void
gs_locked_unregister_root(gs_memory_t * mem,gs_gc_root_t * rp,client_name_t cname)346 gs_locked_unregister_root(gs_memory_t * mem, gs_gc_root_t * rp,
347                           client_name_t cname)
348 {
349     DO_MONITORED(
350                  (*lmem->target->procs.unregister_root)
351                    (lmem->target, rp, cname)
352                  );
353 }
354 static gs_memory_t *
gs_locked_stable(gs_memory_t * mem)355 gs_locked_stable(gs_memory_t * mem)
356 {
357     if (!mem->stable_memory) {
358         gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
359         gs_memory_t *stable;
360 
361         gx_monitor_enter(lmem->monitor);
362         stable = gs_memory_stable(lmem->target);
363         if (stable == lmem->target)
364             mem->stable_memory = mem;
365         else {
366             gs_memory_locked_t *locked_stable = (gs_memory_locked_t *)
367                 gs_alloc_bytes(stable, sizeof(*lmem), "gs_locked_stable");
368 
369             if (locked_stable) {
370                 int code = gs_memory_locked_init(locked_stable, stable);
371 
372                 if (code < 0)
373                     gs_free_object(stable, locked_stable, "gs_locked_stable");
374                 else
375                     mem->stable_memory = (gs_memory_t *)locked_stable;
376             }
377         }
378         gx_monitor_leave(lmem->monitor);
379     }
380     return mem->stable_memory;
381 }
382 static void
gs_locked_status(gs_memory_t * mem,gs_memory_status_t * pstat)383 gs_locked_status(gs_memory_t * mem, gs_memory_status_t * pstat)
384 {
385     DO_MONITORED(
386                  (*lmem->target->procs.status)(lmem->target, pstat)
387                  );
388     pstat->is_thread_safe = true;	/* the monitor (mutex) makes this thread safe */
389 }
390 static void
gs_locked_enable_free(gs_memory_t * mem,bool enable)391 gs_locked_enable_free(gs_memory_t * mem, bool enable)
392 {
393     DO_MONITORED(
394                  (*lmem->target->procs.enable_free)(lmem->target, enable)
395                  );
396 }
397