xref: /plan9/sys/src/cmd/gs/src/ireclaim.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1995, 1996, 1997, 1998, 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: ireclaim.c,v 1.7 2003/09/03 03:22:59 giles Exp $ */
18 /* Interpreter's interface to garbage collector */
19 #include "ghost.h"
20 #include "ierrors.h"
21 #include "gsstruct.h"
22 #include "iastate.h"
23 #include "icontext.h"
24 #include "interp.h"
25 #include "isave.h"		/* for isstate.h */
26 #include "isstate.h"		/* for mem->saved->state */
27 #include "dstack.h"		/* for dsbot, dsp, dict_set_top */
28 #include "estack.h"		/* for esbot, esp */
29 #include "ostack.h"		/* for osbot, osp */
30 #include "opdef.h"		/* for defining init procedure */
31 #include "store.h"		/* for make_array */
32 
33 /* Import preparation and cleanup routines. */
34 extern void ialloc_gc_prepare(gs_ref_memory_t *);
35 
36 /* Forward references */
37 private void gs_vmreclaim(gs_dual_memory_t *, bool);
38 
39 /* Initialize the GC hook in the allocator. */
40 private int ireclaim(gs_dual_memory_t *, int);
41 private int
ireclaim_init(i_ctx_t * i_ctx_p)42 ireclaim_init(i_ctx_t *i_ctx_p)
43 {
44     gs_imemory.reclaim = ireclaim;
45     return 0;
46 }
47 
48 /* GC hook called when the allocator signals a GC is needed (space = -1), */
49 /* or for vmreclaim (space = the space to collect). */
50 private int
ireclaim(gs_dual_memory_t * dmem,int space)51 ireclaim(gs_dual_memory_t * dmem, int space)
52 {
53     bool global;
54     gs_ref_memory_t *mem;
55 
56     if (space < 0) {
57 	/* Determine which allocator exceeded the limit. */
58 	int i;
59 
60 	mem = dmem->space_global;	/* just in case */
61 	for (i = 0; i < countof(dmem->spaces_indexed); ++i) {
62 	    mem = dmem->spaces_indexed[i];
63 	    if (mem == 0)
64 		continue;
65 	    if (mem->gc_status.requested > 0 ||
66 		((gs_ref_memory_t *)mem->stable_memory)->gc_status.requested > 0
67 		)
68 		break;
69 	}
70     } else {
71 	mem = dmem->spaces_indexed[space >> r_space_shift];
72     }
73     if_debug3('0', "[0]GC called, space=%d, requestor=%d, requested=%ld\n",
74 	      space, mem->space, (long)mem->gc_status.requested);
75     global = mem->space != avm_local;
76     /* Since dmem may move, reset the request now. */
77     ialloc_reset_requested(dmem);
78     gs_vmreclaim(dmem, global);
79     ialloc_set_limit(mem);
80     if (space < 0) {
81 	gs_memory_status_t stats;
82 	ulong allocated;
83 
84 	/* If the ammount still allocated after the GC is complete */
85 	/* exceeds the max_vm setting, then return a VMerror       */
86 	gs_memory_status((gs_memory_t *) mem, &stats);
87 	allocated = stats.allocated;
88 	if (mem->stable_memory != (gs_memory_t *)mem) {
89 	    gs_memory_status(mem->stable_memory, &stats);
90 	    allocated += stats.allocated;
91 	}
92 	if (allocated >= mem->gc_status.max_vm) {
93 	    /* We can't satisfy this request within max_vm. */
94 	    return_error(e_VMerror);
95 	}
96     }
97     return 0;
98 }
99 
100 /* Interpreter entry to garbage collector. */
101 private void
gs_vmreclaim(gs_dual_memory_t * dmem,bool global)102 gs_vmreclaim(gs_dual_memory_t *dmem, bool global)
103 {
104     /* HACK: we know the gs_dual_memory_t is embedded in a context state. */
105     i_ctx_t *i_ctx_p =
106 	(i_ctx_t *)((char *)dmem - offset_of(i_ctx_t, memory));
107     gs_ref_memory_t *lmem = dmem->space_local;
108     int code = context_state_store(i_ctx_p);
109     gs_ref_memory_t *memories[5];
110     gs_ref_memory_t *mem;
111     int nmem, i;
112 
113     memories[0] = dmem->space_system;
114     memories[1] = mem = dmem->space_global;
115     nmem = 2;
116     if (lmem != dmem->space_global)
117 	memories[nmem++] = lmem;
118     for (i = nmem; --i >= 0;) {
119 	mem = memories[i];
120 	if (mem->stable_memory != (gs_memory_t *)mem)
121 	    memories[nmem++] = (gs_ref_memory_t *)mem->stable_memory;
122     }
123 
124     /****** ABORT IF code < 0 ******/
125     for (i = nmem; --i >= 0; )
126 	alloc_close_chunk(memories[i]);
127 
128     /* Prune the file list so it won't retain potentially collectible */
129     /* files. */
130 
131     for (i = (global ? i_vm_system : i_vm_local);
132 	 i < countof(dmem->spaces_indexed);
133 	 ++i
134 	 ) {
135 	gs_ref_memory_t *mem = dmem->spaces_indexed[i];
136 
137 	if (mem == 0 || (i > 0 && mem == dmem->spaces_indexed[i - 1]))
138 	    continue;
139 	if (mem->stable_memory != (gs_memory_t *)mem)
140 	    ialloc_gc_prepare((gs_ref_memory_t *)mem->stable_memory);
141 	for (;; mem = &mem->saved->state) {
142 	    ialloc_gc_prepare(mem);
143 	    if (mem->saved == 0)
144 		break;
145 	}
146     }
147 
148     /* Do the actual collection. */
149 
150     {
151 	void *ctxp = i_ctx_p;
152 	gs_gc_root_t context_root;
153 
154 	gs_register_struct_root((gs_memory_t *)lmem, &context_root,
155 				&ctxp, "i_ctx_p root");
156 	GS_RECLAIM(&dmem->spaces, global);
157 	gs_unregister_root((gs_memory_t *)lmem, &context_root, "i_ctx_p root");
158 	i_ctx_p = ctxp;
159 	dmem = &i_ctx_p->memory;
160     }
161 
162     /* Update caches not handled by context_state_load. */
163 
164     *systemdict = *ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 1);
165 
166     /* Reload the context state. */
167 
168     code = context_state_load(i_ctx_p);
169     /****** ABORT IF code < 0 ******/
170 
171     /* Update the cached value pointers in names. */
172 
173     dicts_gc_cleanup();
174 
175     /* Reopen the active chunks. */
176 
177     for (i = 0; i < nmem; ++i)
178 	alloc_open_chunk(memories[i]);
179 }
180 
181 /* ------ Initialization procedure ------ */
182 
183 const op_def ireclaim_l2_op_defs[] =
184 {
185     op_def_end(ireclaim_init)
186 };
187