Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1998 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: gxpageq.c,v 1.5 2002/06/16 05:48:56 lpd Exp $ */
18
/* Page queue implementation */
19
 
20
/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
21
 
22
#include "gx.h"
23
#include "gxdevice.h"
24
#include "gxclist.h"
25
#include "gxpageq.h"
26
#include "gserrors.h"
27
#include "gsstruct.h"
28
 
29
/* Define the structure implementation for a page queue. */
30
struct gx_page_queue_s {
31
    gs_memory_t *memory;	/* allocator used to allocate entries */
32
    gx_monitor_t *monitor;	/* used to serialize access to this structure */
33
    int entry_count;		/* # elements in page_queue */
34
    bool dequeue_in_progress;	/* true between start/ & end_dequeue */
35
    gx_semaphore_t *render_req_sema;	/* sema signalled when page queued */
36
    bool enable_render_done_signal;	/* enable signals to render_done_sema */
37
    gx_semaphore_t *render_done_sema;	/* semaphore signaled when (partial) page rendered */
38
    gx_page_queue_entry_t *last_in;	/* if <> 0, Last-in queue entry */
39
    gx_page_queue_entry_t *first_in;	/* if <> 0, First-in queue entry */
40
    gx_page_queue_entry_t *reserve_entry;	/* spare allocation */
41
};
42
 
43
/*
44
 * Null initializer for entry page_info (used by gx_page_queue_add_page() ).
45
 */
46
private const gx_band_page_info_t null_page_info = { PAGE_INFO_NULL_VALUES };
47
 
48
#define private_st_gx_page_queue()\
49
  gs_private_st_ptrs4(st_gx_page_queue, gx_page_queue_t, "gx_page_queue",\
50
    gx_page_queue_enum_ptrs, gx_page_queue_reloc_ptrs,\
51
    monitor, first_in, last_in, reserve_entry);
52
 
53
/* ------------------- Global Data ----------------------- */
54
 
55
/* Structure descriptor for GC */
56
private_st_gx_page_queue_entry();
57
private_st_gx_page_queue();
58
 
59
/* ------------ Forward Decl's --------------------------- */
60
private gx_page_queue_entry_t *	/* removed entry, 0 if none avail */
61
    gx_page_queue_remove_first(
62
			       gx_page_queue_t * queue	/* page queue to retrieve from */
63
			       );
64
 
65
 
66
/* --------------------Procedures------------------------- */
67
 
68
/* Allocate a page queue. */
69
gx_page_queue_t *
70
gx_page_queue_alloc(gs_memory_t *mem)
71
{
72
    return gs_alloc_struct(mem, gx_page_queue_t, &st_gx_page_queue,
73
			   "gx_page_queue_alloc");
74
}
75
 
76
/* ------- page_queue_entry alloc/free --------- */
77
 
78
/* Allocate & init a gx_page_queue_entry */
79
gx_page_queue_entry_t *		/* rets ptr to allocated object, 0 if VM error */
80
gx_page_queue_entry_alloc(
81
			  gx_page_queue_t * queue	/* queue that entry is being alloc'd for */
82
)
83
{
84
    gx_page_queue_entry_t *entry
85
    = gs_alloc_struct(queue->memory, gx_page_queue_entry_t,
86
		      &st_gx_page_queue_entry, "gx_page_queue_entry_alloc");
87
 
88
    if (entry != 0) {
89
	entry->next = 0;
90
	entry->queue = queue;
91
    }
92
    return entry;
93
}
94
 
95
/* Free a gx_page_queue_entry allocated w/gx_page_queue_entry_alloc */
96
void
97
gx_page_queue_entry_free(
98
			    gx_page_queue_entry_t * entry	/* entry to free up */
99
)
100
{
101
    gs_free_object(entry->queue->memory, entry, "gx_page_queue_entry_free");
102
}
103
 
104
/* Free the clist resources held by a gx_page_queue_entry_t */
105
void
106
gx_page_queue_entry_free_page_info(
107
			    gx_page_queue_entry_t * entry	/* entry to free up */
108
)
109
{
110
    clist_close_page_info( &entry->page_info );
111
}
112
 
113
/* -------- page_queue init/dnit ---------- */
114
 
115
/* Initialize a gx_page_queue object */
116
int				/* -ve error code, or 0 */
117
gx_page_queue_init(
118
		   gx_page_queue_t * queue,	/* page queue to init */
119
		   gs_memory_t * memory	/* allocator for dynamic memory */
120
)
121
{
122
    queue->memory = memory;
123
    queue->monitor = gx_monitor_alloc(memory);	/* alloc monitor to serialize */
124
    queue->entry_count = 0;
125
    queue->dequeue_in_progress = false;
126
    queue->render_req_sema = gx_semaphore_alloc(memory);
127
    queue->enable_render_done_signal = false;
128
    queue->render_done_sema = gx_semaphore_alloc(memory);
129
    queue->first_in = queue->last_in = 0;
130
    queue->reserve_entry = gx_page_queue_entry_alloc(queue);
131
 
132
    if (queue->monitor && queue->render_req_sema && queue->render_done_sema
133
	&& queue->reserve_entry)
134
	return 0;
135
    else {
136
	gx_page_queue_dnit(queue);
137
	return gs_error_VMerror;
138
    }
139
}
140
 
141
/* Dnitialize a gx_page_queue object */
142
void
143
gx_page_queue_dnit(
144
		      gx_page_queue_t * queue	/* page queue to dnit */
145
)
146
{
147
    /* Deallocate any left-over queue entries */
148
    gx_page_queue_entry_t *entry;
149
 
150
    while ((entry = gx_page_queue_remove_first(queue)) != 0) {
151
	gx_page_queue_entry_free_page_info(entry);
152
	gx_page_queue_entry_free(entry);
153
    }
154
 
155
    /* Free dynamic objects */
156
    if (queue->monitor) {
157
	gx_monitor_free(queue->monitor);
158
	queue->monitor = 0;
159
    }
160
    if (queue->render_req_sema) {
161
	gx_semaphore_free(queue->render_req_sema);
162
	queue->render_req_sema = 0;
163
    }
164
    if (queue->render_done_sema) {
165
	gx_semaphore_free(queue->render_done_sema);
166
	queue->render_done_sema = 0;
167
    }
168
    if (queue->reserve_entry) {
169
	gx_page_queue_entry_free(queue->reserve_entry);
170
	queue->reserve_entry = 0;
171
    }
172
}
173
 
174
/* -------- low-level queue add/remove ---------- */
175
 
176
/* Retrieve & remove firstin queue entry */
177
private gx_page_queue_entry_t *	/* removed entry, 0 if none avail */
178
gx_page_queue_remove_first(
179
			      gx_page_queue_t * queue	/* page queue to retrieve from */
180
)
181
{
182
    gx_page_queue_entry_t *entry = 0;	/* assume failure */
183
 
184
    /* Enter monitor */
185
    gx_monitor_enter(queue->monitor);
186
 
187
    /* Get the goods */
188
    if (queue->entry_count) {
189
	entry = queue->first_in;
190
	queue->first_in = entry->next;
191
	if (queue->last_in == entry)
192
	    queue->last_in = 0;
193
	--queue->entry_count;
194
    }
195
    /* exit monitor */
196
    gx_monitor_leave(queue->monitor);
197
 
198
    return entry;
199
}
200
 
201
/* Add entry to queue at end */
202
private void
203
gx_page_queue_add_last(
204
			  gx_page_queue_entry_t * entry	/* entry to add */
205
)
206
{
207
    gx_page_queue_t *queue = entry->queue;
208
 
209
    /* Enter monitor */
210
    gx_monitor_enter(queue->monitor);
211
 
212
    /* Add the goods */
213
    entry->next = 0;
214
    if (queue->last_in != 0)
215
	queue->last_in->next = entry;
216
    queue->last_in = entry;
217
    if (queue->first_in == 0)
218
	queue->first_in = entry;
219
    ++queue->entry_count;
220
 
221
    /* exit monitor */
222
    gx_monitor_leave(queue->monitor);
223
}
224
 
225
/* --------- low-level synchronization ---------- */
226
 
227
/* Wait for a single page to finish rendering (if any pending) */
228
int				/* rets 0 if no pages were waiting for rendering, 1 if actually waited */
229
gx_page_queue_wait_one_page(
230
			       gx_page_queue_t * queue	/* queue to wait on */
231
)
232
{
233
    int code;
234
 
235
    gx_monitor_enter(queue->monitor);
236
    if (!queue->entry_count && !queue->dequeue_in_progress) {
237
	code = 0;
238
	gx_monitor_leave(queue->monitor);
239
    } else {
240
	/* request acknowledgement on render done */
241
	queue->enable_render_done_signal = true;
242
 
243
	/* exit monitor & wait for acknowlegement */
244
	gx_monitor_leave(queue->monitor);
245
	gx_semaphore_wait(queue->render_done_sema);
246
	code = 1;
247
    }
248
    return code;
249
}
250
 
251
/* Wait for page queue to become empty */
252
void
253
gx_page_queue_wait_until_empty(
254
				  gx_page_queue_t * queue	/* page queue to wait on */
255
)
256
{
257
    while (gx_page_queue_wait_one_page(queue));
258
}
259
 
260
/* -----------  Synchronized page_queue get/put routines ------ */
261
 
262
/* Add an entry to page queue for rendering w/sync to renderer */
263
void
264
gx_page_queue_enqueue(
265
			 gx_page_queue_entry_t * entry	/* entry to add */
266
)
267
{
268
    gx_page_queue_t *queue = entry->queue;
269
 
270
    /* Add the goods to queue, & signal it */
271
    gx_page_queue_add_last(entry);
272
    gx_semaphore_signal(queue->render_req_sema);
273
}
274
 
275
/* Add page to a page queue */
276
/* Even if an error is returned, entry will have been added to queue! */
277
int				/* rets 0 ok, gs_error_VMerror if error */
278
gx_page_queue_add_page(
279
			  gx_page_queue_t * queue,	/* page queue to add to */
280
			  gx_page_queue_action_t action,	/* action code to queue */
281
			  const gx_band_page_info_t * page_info,  /* bandinfo incl. bandlist (or 0) */
282
			  int page_count	/* see comments in gdevprna.c */
283
)
284
{
285
    int code = 0;
286
 
287
    /* Allocate a new page queue entry */
288
    gx_page_queue_entry_t *entry
289
    = gx_page_queue_entry_alloc(queue);
290
 
291
    if (!entry) {
292
	/* Use reserve page queue entry */
293
	gx_monitor_enter(queue->monitor);	/* not strictly necessary */
294
	entry = queue->reserve_entry;
295
	queue->reserve_entry = 0;
296
	gx_monitor_leave(queue->monitor);
297
    }
298
    /* Fill in page queue entry with info from device */
299
    entry->action = action;
300
    if (page_info != 0)
301
	entry->page_info = *page_info;
302
    else
303
	entry->page_info = null_page_info;
304
    entry->num_copies = page_count;
305
 
306
    /* Stick onto page queue & signal */
307
    gx_page_queue_enqueue(entry);
308
 
309
    /* If a new reserve entry is needed, wait till enough mem is avail */
310
    while (!queue->reserve_entry) {
311
	queue->reserve_entry = gx_page_queue_entry_alloc(queue);
312
	if (!queue->reserve_entry && !gx_page_queue_wait_one_page(queue)) {
313
	    /* Should never happen: all pages rendered & still can't get memory: give up! */
314
	    code = gs_note_error(gs_error_Fatal);
315
	    break;
316
	}
317
    }
318
    return code;
319
}
320
 
321
/* Wait for & get next page queue entry */
322
gx_page_queue_entry_t *		/* removed entry */
323
gx_page_queue_start_dequeue(
324
			       gx_page_queue_t * queue	/* page queue to retrieve from */
325
)
326
{
327
    gx_semaphore_wait(queue->render_req_sema);
328
    queue->dequeue_in_progress = true;
329
    return gx_page_queue_remove_first(queue);
330
}
331
 
332
/* After rendering page gotten w/gx_page_queue_dequeue, call this to ack */
333
void
334
gx_page_queue_finish_dequeue(
335
				gx_page_queue_entry_t * entry	/* entry that was retrieved to delete */
336
)
337
{
338
    gx_page_queue_t *queue = entry->queue;
339
 
340
    gx_monitor_enter(queue->monitor);
341
    if (queue->enable_render_done_signal) {
342
	queue->enable_render_done_signal = false;
343
	gx_semaphore_signal(queue->render_done_sema);
344
    }
345
    queue->dequeue_in_progress = false;
346
 
347
    /*
348
     * Delete the previously-allocated entry, do inside monitor in case
349
     * this is the reserve entry & is the only memory in the universe;
350
     * in that case gx_page_queue_add_page won't be looking for this
351
     * until the monitor is exited.
352
     * In this implementation of the page queue, clist and queue entries
353
     * are managed together, so free the clist just before freeing the entry.
354
     */
355
    gx_page_queue_entry_free_page_info(entry);
356
    gx_page_queue_entry_free(entry);
357
 
358
    gx_monitor_leave(queue->monitor);
359
}