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