Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 1995, 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: zvmem.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
18
/* "Virtual memory" operators */
19
#include "ghost.h"
20
#include "gsstruct.h"
21
#include "oper.h"
22
#include "estack.h"		/* for checking in restore */
23
#include "ialloc.h"
24
#include "idict.h"		/* ditto */
25
#include "igstate.h"
26
#include "isave.h"
27
#include "dstack.h"
28
#include "stream.h"		/* for files.h */
29
#include "files.h"		/* for e-stack processing */
30
#include "store.h"
31
#include "gsmatrix.h"		/* for gsstate.h */
32
#include "gsstate.h"
33
 
34
/* Define whether we validate memory before/after save/restore. */
35
/* Note that we only actually do this if DEBUG is set and -Z? is selected. */
36
private const bool I_VALIDATE_BEFORE_SAVE = true;
37
private const bool I_VALIDATE_AFTER_SAVE = true;
38
private const bool I_VALIDATE_BEFORE_RESTORE = true;
39
private const bool I_VALIDATE_AFTER_RESTORE = true;
40
 
41
/* 'Save' structure */
42
typedef struct vm_save_s vm_save_t;
43
struct vm_save_s {
44
    gs_state *gsave;		/* old graphics state */
45
};
46
 
47
gs_private_st_ptrs1(st_vm_save, vm_save_t, "savetype",
48
		    vm_save_enum_ptrs, vm_save_reloc_ptrs, gsave);
49
 
50
/* Clean up the stacks and validate storage. */
51
private void
52
ivalidate_clean_spaces(i_ctx_t *i_ctx_p)
53
{
54
    if (gs_debug_c('?')) {
55
	ref_stack_cleanup(&d_stack);
56
	ref_stack_cleanup(&e_stack);
57
	ref_stack_cleanup(&o_stack);
58
	ivalidate_spaces();
59
    }
60
}
61
 
62
/* - save <save> */
63
int
64
zsave(i_ctx_t *i_ctx_p)
65
{
66
    os_ptr op = osp;
67
    uint space = icurrent_space;
68
    vm_save_t *vmsave;
69
    ulong sid;
70
    int code;
71
    gs_state *prev;
72
 
73
    if (I_VALIDATE_BEFORE_SAVE)
74
	ivalidate_clean_spaces(i_ctx_p);
75
    ialloc_set_space(idmemory, avm_local);
76
    vmsave = ialloc_struct(vm_save_t, &st_vm_save, "zsave");
77
    ialloc_set_space(idmemory, space);
78
    if (vmsave == 0)
79
	return_error(e_VMerror);
80
    sid = alloc_save_state(idmemory, vmsave);
81
    if (sid == 0) {
82
	ifree_object(vmsave, "zsave");
83
	return_error(e_VMerror);
84
    }
85
    if_debug2('u', "[u]vmsave 0x%lx, id = %lu\n",
86
	      (ulong) vmsave, (ulong) sid);
87
    code = gs_gsave_for_save(igs, &prev);
88
    if (code < 0)
89
	return code;
90
    code = gs_gsave(igs);
91
    if (code < 0)
92
	return code;
93
    vmsave->gsave = prev;
94
    push(1);
95
    make_tav(op, t_save, 0, saveid, sid);
96
    if (I_VALIDATE_AFTER_SAVE)
97
	ivalidate_clean_spaces(i_ctx_p);
98
    return 0;
99
}
100
 
101
/* <save> restore - */
102
private int restore_check_operand(os_ptr, alloc_save_t **, gs_dual_memory_t *);
103
private int restore_check_stack(const ref_stack_t *, const alloc_save_t *, bool);
104
private void restore_fix_stack(ref_stack_t *, const alloc_save_t *, bool);
105
int
106
zrestore(i_ctx_t *i_ctx_p)
107
{
108
    os_ptr op = osp;
109
    alloc_save_t *asave;
110
    bool last;
111
    vm_save_t *vmsave;
112
    int code = restore_check_operand(op, &asave, idmemory);
113
 
114
    if (code < 0)
115
	return code;
116
    if_debug2('u', "[u]vmrestore 0x%lx, id = %lu\n",
117
	      (ulong) alloc_save_client_data(asave),
118
	      (ulong) op->value.saveid);
119
    if (I_VALIDATE_BEFORE_RESTORE)
120
	ivalidate_clean_spaces(i_ctx_p);
121
    /* Check the contents of the stacks. */
122
    osp--;
123
    {
124
	int code;
125
 
126
	if ((code = restore_check_stack(&o_stack, asave, false)) < 0 ||
127
	    (code = restore_check_stack(&e_stack, asave, true)) < 0 ||
128
	    (code = restore_check_stack(&d_stack, asave, false)) < 0
129
	    ) {
130
	    osp++;
131
	    return code;
132
	}
133
    }
134
    /* Reset l_new in all stack entries if the new save level is zero. */
135
    /* Also do some special fixing on the e-stack. */
136
    restore_fix_stack(&o_stack, asave, false);
137
    restore_fix_stack(&e_stack, asave, true);
138
    restore_fix_stack(&d_stack, asave, false);
139
    /* Iteratively restore the state of memory, */
140
    /* also doing a grestoreall at each step. */
141
    do {
142
	vmsave = alloc_save_client_data(alloc_save_current(idmemory));
143
	/* Restore the graphics state. */
144
	gs_grestoreall_for_restore(igs, vmsave->gsave);
145
	/*
146
	 * If alloc_save_space decided to do a second save, the vmsave
147
	 * object was allocated one save level less deep than the
148
	 * current level, so ifree_object won't actually free it;
149
	 * however, it points to a gsave object that definitely
150
	 * *has* been freed.  In order not to trip up the garbage
151
	 * collector, we clear the gsave pointer now.
152
	 */
153
	vmsave->gsave = 0;
154
	/* Now it's safe to restore the state of memory. */
155
	last = alloc_restore_state_step(asave);
156
    }
157
    while (!last);
158
    {
159
	uint space = icurrent_space;
160
 
161
	ialloc_set_space(idmemory, avm_local);
162
	ifree_object(vmsave, "zrestore");
163
	ialloc_set_space(idmemory, space);
164
    }
165
    dict_set_top();		/* reload dict stack cache */
166
    if (I_VALIDATE_AFTER_RESTORE)
167
	ivalidate_clean_spaces(i_ctx_p);
168
    /* If the i_ctx_p LockFilePermissions is true, but the userparams */
169
    /* we just restored is false, we need to make sure that we do not */
170
    /* cause an 'invalidaccess' in setuserparams. Temporarily set     */
171
    /* LockFilePermissions false until the gs_lev2.ps can do a        */
172
    /* setuserparams from the restored userparam dictionary.          */
173
    i_ctx_p->LockFilePermissions = false;
174
    return 0;
175
}
176
/* Check the operand of a restore. */
177
private int
178
restore_check_operand(os_ptr op, alloc_save_t ** pasave,
179
		      gs_dual_memory_t *idmem)
180
{
181
    vm_save_t *vmsave;
182
    ulong sid;
183
    alloc_save_t *asave;
184
 
185
    check_type(*op, t_save);
186
    vmsave = r_ptr(op, vm_save_t);
187
    if (vmsave == 0)		/* invalidated save */
188
	return_error(e_invalidrestore);
189
    sid = op->value.saveid;
190
    asave = alloc_find_save(idmem, sid);
191
    if (asave == 0)
192
	return_error(e_invalidrestore);
193
    *pasave = asave;
194
    return 0;
195
}
196
/* Check a stack to make sure all its elements are older than a save. */
197
private int
198
restore_check_stack(const ref_stack_t * pstack, const alloc_save_t * asave,
199
		    bool is_estack)
200
{
201
    ref_stack_enum_t rsenum;
202
 
203
    ref_stack_enum_begin(&rsenum, pstack);
204
    do {
205
	const ref *stkp = rsenum.ptr;
206
	uint size = rsenum.size;
207
 
208
	for (; size; stkp++, size--) {
209
	    const void *ptr;
210
 
211
	    switch (r_type(stkp)) {
212
		case t_array:
213
		    ptr = stkp->value.refs;
214
		    break;
215
		case t_dictionary:
216
		    ptr = stkp->value.pdict;
217
		    break;
218
		case t_file:
219
		    /* Don't check executable or closed literal */
220
		    /* files on the e-stack. */
221
		    {
222
			stream *s;
223
 
224
			if (is_estack &&
225
			    (r_has_attr(stkp, a_executable) ||
226
			     file_is_invalid(s, stkp))
227
			    )
228
			    continue;
229
		    }
230
		    ptr = stkp->value.pfile;
231
		    break;
232
		case t_name:
233
		    /* Names are special because of how they are allocated. */
234
		    if (alloc_name_is_since_save((const gs_memory_t *)pstack->memory,
235
						 stkp, asave))
236
			return_error(e_invalidrestore);
237
		    continue;
238
		case t_string:
239
		    /* Don't check empty executable strings */
240
		    /* on the e-stack. */
241
		    if (r_size(stkp) == 0 &&
242
			r_has_attr(stkp, a_executable) && is_estack
243
			)
244
			continue;
245
		    ptr = stkp->value.bytes;
246
		    break;
247
		case t_mixedarray:
248
		case t_shortarray:
249
		    ptr = stkp->value.packed;
250
		    break;
251
		case t_device:
252
		    ptr = stkp->value.pdevice;
253
		    break;
254
		case t_fontID:
255
		case t_struct:
256
		case t_astruct:
257
		    ptr = stkp->value.pstruct;
258
		    break;
259
		default:
260
		    continue;
261
	    }
262
	    if (alloc_is_since_save(ptr, asave))
263
		return_error(e_invalidrestore);
264
	}
265
    } while (ref_stack_enum_next(&rsenum));
266
    return 0;		/* OK */
267
}
268
/*
269
 * If the new save level is zero, fix up the contents of a stack
270
 * by clearing the l_new bit in all the entries (since we can't tolerate
271
 * values with l_new set if the save level is zero).
272
 * Also, in any case, fix up the e-stack by replacing empty executable
273
 * strings and closed executable files that are newer than the save
274
 * with canonical ones that aren't.
275
 *
276
 * Note that this procedure is only called if restore_check_stack succeeded.
277
 */
278
private void
279
restore_fix_stack(ref_stack_t * pstack, const alloc_save_t * asave,
280
		  bool is_estack)
281
{
282
    ref_stack_enum_t rsenum;
283
 
284
    ref_stack_enum_begin(&rsenum, pstack);
285
    do {
286
	ref *stkp = rsenum.ptr;
287
	uint size = rsenum.size;
288
 
289
	for (; size; stkp++, size--) {
290
	    r_clear_attrs(stkp, l_new);		/* always do it, no harm */
291
	    if (is_estack) {
292
		ref ofile;
293
 
294
		ref_assign(&ofile, stkp);
295
		switch (r_type(stkp)) {
296
		    case t_string:
297
			if (r_size(stkp) == 0 &&
298
			    alloc_is_since_save(stkp->value.bytes,
299
						asave)
300
			    ) {
301
			    make_empty_const_string(stkp,
302
						    avm_foreign);
303
			    break;
304
			}
305
			continue;
306
		    case t_file:
307
			if (alloc_is_since_save(stkp->value.pfile,
308
						asave)
309
			    ) {
310
			    make_invalid_file(stkp);
311
			    break;
312
			}
313
			continue;
314
		    default:
315
			continue;
316
		}
317
		r_copy_attrs(stkp, a_all | a_executable,
318
			     &ofile);
319
	    }
320
	}
321
    } while (ref_stack_enum_next(&rsenum));
322
}
323
 
324
/* - vmstatus <save_level> <vm_used> <vm_maximum> */
325
private int
326
zvmstatus(i_ctx_t *i_ctx_p)
327
{
328
    os_ptr op = osp;
329
    gs_memory_status_t mstat, dstat;
330
 
331
    gs_memory_status(imemory, &mstat);
332
    if (imemory == imemory_global) {
333
	gs_memory_status_t sstat;
334
 
335
	gs_memory_status(imemory_system, &sstat);
336
	mstat.allocated += sstat.allocated;
337
	mstat.used += sstat.used;
338
    }
339
    gs_memory_status(imemory->non_gc_memory, &dstat);
340
    push(3);
341
    make_int(op - 2, imemory_save_level(iimemory_local));
342
    make_int(op - 1, mstat.used);
343
    make_int(op, mstat.allocated + dstat.allocated - dstat.used);
344
    return 0;
345
}
346
 
347
/* ------ Non-standard extensions ------ */
348
 
349
/* <save> .forgetsave - */
350
private int
351
zforgetsave(i_ctx_t *i_ctx_p)
352
{
353
    os_ptr op = osp;
354
    alloc_save_t *asave;
355
    vm_save_t *vmsave;
356
    int code = restore_check_operand(op, &asave, idmemory);
357
 
358
    if (code < 0)
359
	return 0;
360
    vmsave = alloc_save_client_data(asave);
361
    /* Reset l_new in all stack entries if the new save level is zero. */
362
    restore_fix_stack(&o_stack, asave, false);
363
    restore_fix_stack(&e_stack, asave, false);
364
    restore_fix_stack(&d_stack, asave, false);
365
    /*
366
     * Forget the gsaves, by deleting the bottom gstate on
367
     * the current stack and the top one on the saved stack and then
368
     * concatenating the stacks together.
369
     */
370
    {
371
	gs_state *pgs = igs;
372
	gs_state *last;
373
 
374
	while (gs_state_saved(last = gs_state_saved(pgs)) != 0)
375
	    pgs = last;
376
	gs_state_swap_saved(last, vmsave->gsave);
377
	gs_grestore(last);
378
	gs_grestore(last);
379
    }
380
    /* Forget the save in the memory manager. */
381
    alloc_forget_save(asave);
382
    {
383
	uint space = icurrent_space;
384
 
385
	ialloc_set_space(idmemory, avm_local);
386
	/* See above for why we clear the gsave pointer here. */
387
	vmsave->gsave = 0;
388
	ifree_object(vmsave, "zrestore");
389
	ialloc_set_space(idmemory, space);
390
    }
391
    pop(1);
392
    return 0;
393
}
394
 
395
/* ------ Initialization procedure ------ */
396
 
397
const op_def zvmem_op_defs[] =
398
{
399
    {"1.forgetsave", zforgetsave},
400
    {"1restore", zrestore},
401
    {"0save", zsave},
402
    {"0vmstatus", zvmstatus},
403
    op_def_end(0)
404
};