2 #include "ev-job-queue.h"
4 /* Like glib calling convention, all functions with _locked in their name assume
5 * that we've already locked the doc mutex and can freely and safely access
8 GCond *render_cond = NULL;
9 GMutex *ev_queue_mutex = NULL;
11 static GQueue *links_queue = NULL;
12 static GQueue *render_queue_high = NULL;
13 static GQueue *render_queue_low = NULL;
14 static GQueue *thumbnail_queue_high = NULL;
15 static GQueue *thumbnail_queue_low = NULL;
16 static GQueue *load_queue = NULL;
17 static GQueue *save_queue = NULL;
18 static GQueue *fonts_queue = NULL;
19 static GQueue *print_queue = NULL;
21 /* Queues used for backends supporting EvAsyncRender interface,
22 they are executed on the main thread */
23 static GQueue *async_render_queue_high = NULL;
24 static GQueue *async_render_queue_low = NULL;
25 static gboolean async_rendering = FALSE;
27 static void ev_job_queue_run_next (void);
30 remove_job_from_queue_locked (GQueue *queue, EvJob *job)
34 list = g_queue_find (queue, job);
36 g_object_unref (G_OBJECT (job));
37 g_queue_delete_link (queue, list);
45 remove_job_from_async_queue (GQueue *queue, EvJob *job)
47 return remove_job_from_queue_locked (queue, job);
51 add_job_to_async_queue (GQueue *queue, EvJob *job)
54 g_queue_push_tail (queue, job);
58 * add_job_to_queue_locked:
59 * @queue: a #GQueue where the #EvJob will be added.
60 * @job: an #EvJob to be added to the specified #GQueue.
62 * Add the #EvJob to the specified #GQueue and woke up the ev_render_thread who
63 * is waiting for render_cond.
66 add_job_to_queue_locked (GQueue *queue,
70 g_queue_push_tail (queue, job);
71 g_cond_broadcast (render_cond);
76 * @job: the object that signal will be reseted.
78 * It does emit the job finished signal and returns %FALSE.
83 notify_finished (GObject *job)
85 ev_job_finished (EV_JOB (job));
92 * @job: the #EvJob that has been handled.
94 * It does finish the job last work and look if there is any more job to be
98 job_finished_cb (EvJob *job)
100 g_object_unref (job);
101 async_rendering = FALSE;
102 ev_job_queue_run_next ();
107 * @job: the #EvJob to be handled.
109 * First, it does check if the job is async and then it does attend it if
110 * possible giving a failed assertion otherwise. If the job isn't async it does
111 * attend it and notify that the job has been finished.
114 handle_job (EvJob *job)
116 g_object_ref (G_OBJECT (job));
118 if (EV_JOB (job)->async) {
119 async_rendering = TRUE;
120 if (EV_IS_JOB_RENDER (job)) {
121 g_signal_connect (job, "finished",
122 G_CALLBACK (job_finished_cb), NULL);
124 g_assert_not_reached ();
128 if (EV_IS_JOB_THUMBNAIL (job))
129 ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job));
130 else if (EV_IS_JOB_LINKS (job))
131 ev_job_links_run (EV_JOB_LINKS (job));
132 else if (EV_IS_JOB_LOAD (job))
133 ev_job_load_run (EV_JOB_LOAD (job));
134 else if (EV_IS_JOB_SAVE (job))
135 ev_job_save_run (EV_JOB_SAVE (job));
136 else if (EV_IS_JOB_RENDER (job))
137 ev_job_render_run (EV_JOB_RENDER (job));
138 else if (EV_IS_JOB_FONTS (job))
139 ev_job_fonts_run (EV_JOB_FONTS (job));
140 else if (EV_IS_JOB_PRINT (job))
141 ev_job_print_run (EV_JOB_PRINT (job));
143 if (!EV_JOB (job)->async) {
144 /* We let the idle own a ref, as we (the queue) are done with the job. */
145 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
146 (GSourceFunc) notify_finished,
153 * search_for_jobs_unlocked:
155 * Check if there is any job at the synchronized queues and return any existing
156 * job in them taking in account the next priority:
158 * render_queue_high >
159 * thumbnail_queue_high >
163 * thumbnail_queue_low >
167 * Returns: an available #EvJob in the queues taking in account stablished queue
171 search_for_jobs_unlocked (void)
175 job = (EvJob *) g_queue_pop_head (render_queue_high);
179 job = (EvJob *) g_queue_pop_head (thumbnail_queue_high);
183 job = (EvJob *) g_queue_pop_head (render_queue_low);
187 job = (EvJob *) g_queue_pop_head (links_queue);
191 job = (EvJob *) g_queue_pop_head (load_queue);
195 job = (EvJob *) g_queue_pop_head (save_queue);
199 job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
203 job = (EvJob *) g_queue_pop_head (fonts_queue);
207 job = (EvJob *) g_queue_pop_head (print_queue);
215 * no_jobs_available_unlocked:
217 * Looks if there is any job at render, links, load, thumbnail. fonts and print
220 * Returns: %TRUE if the render, links, load, thumbnail, fonts and print queues
221 * are empty, %FALSE in other case.
224 no_jobs_available_unlocked (void)
226 return g_queue_is_empty (render_queue_high)
227 && g_queue_is_empty (render_queue_low)
228 && g_queue_is_empty (links_queue)
229 && g_queue_is_empty (load_queue)
230 && g_queue_is_empty (save_queue)
231 && g_queue_is_empty (thumbnail_queue_high)
232 && g_queue_is_empty (thumbnail_queue_low)
233 && g_queue_is_empty (fonts_queue)
234 && g_queue_is_empty (print_queue);
237 /* the thread mainloop function */
240 * @data: data passed to the thread.
242 * The thread mainloop function. It does wait for any available job in synced
243 * queues to handle it.
245 * Returns: the return value of the thread, which will be returned by
249 ev_render_thread (gpointer data)
254 g_mutex_lock (ev_queue_mutex);
255 if (no_jobs_available_unlocked ()) {
256 g_cond_wait (render_cond, ev_queue_mutex);
259 job = search_for_jobs_unlocked ();
260 g_mutex_unlock (ev_queue_mutex);
262 /* Now that we have our job, we handle it */
265 g_object_unref (G_OBJECT (job));
273 * ev_job_queue_run_next:
275 * It does look for any job on the render high priority queue first and after
276 * in the render low priority one, and then it does handle it.
279 ev_job_queue_run_next (void)
283 job = (EvJob *) g_queue_pop_head (async_render_queue_high);
286 job = (EvJob *) g_queue_pop_head (async_render_queue_low);
289 /* Now that we have our job, we handle it */
292 g_object_unref (G_OBJECT (job));
296 /* Public Functions */
300 * Creates a new cond, new mutex, a thread for evince job handling and inits
304 ev_job_queue_init (void)
306 if (!g_thread_supported ()) g_thread_init (NULL);
308 render_cond = g_cond_new ();
309 ev_queue_mutex = g_mutex_new ();
311 links_queue = g_queue_new ();
312 load_queue = g_queue_new ();
313 save_queue = g_queue_new ();
314 render_queue_high = g_queue_new ();
315 render_queue_low = g_queue_new ();
316 async_render_queue_high = g_queue_new ();
317 async_render_queue_low = g_queue_new ();
318 thumbnail_queue_high = g_queue_new ();
319 thumbnail_queue_low = g_queue_new ();
320 fonts_queue = g_queue_new ();
321 print_queue = g_queue_new ();
323 g_thread_create (ev_render_thread, NULL, FALSE, NULL);
328 find_queue (EvJob *job,
329 EvJobPriority priority)
331 if (EV_JOB (job)->async) {
332 if (EV_IS_JOB_RENDER (job)) {
333 if (priority == EV_JOB_PRIORITY_HIGH)
334 return async_render_queue_high;
336 return async_render_queue_low;
339 if (EV_IS_JOB_RENDER (job)) {
340 if (priority == EV_JOB_PRIORITY_HIGH)
341 return render_queue_high;
343 return render_queue_low;
344 } else if (EV_IS_JOB_THUMBNAIL (job)) {
345 if (priority == EV_JOB_PRIORITY_HIGH)
346 return thumbnail_queue_high;
348 return thumbnail_queue_low;
349 } else if (EV_IS_JOB_LOAD (job)) {
350 /* the priority doesn't effect load */
352 } else if (EV_IS_JOB_SAVE (job)) {
353 /* the priority doesn't effect save */
355 } else if (EV_IS_JOB_LINKS (job)) {
356 /* the priority doesn't effect links */
358 } else if (EV_IS_JOB_FONTS (job)) {
359 /* the priority doesn't effect fonts */
361 } else if (EV_IS_JOB_PRINT (job)) {
362 /* the priority doesn't effect print */
367 g_assert_not_reached ();
372 ev_job_queue_add_job (EvJob *job,
373 EvJobPriority priority)
377 g_return_if_fail (EV_IS_JOB (job));
379 queue = find_queue (job, priority);
381 if (!EV_JOB (job)->async) {
382 g_mutex_lock (ev_queue_mutex);
383 add_job_to_queue_locked (queue, job);
384 g_mutex_unlock (ev_queue_mutex);
386 add_job_to_async_queue (queue, job);
387 if (!async_rendering) {
388 ev_job_queue_run_next ();
394 move_job_async (EvJob *job, GQueue *old_queue, GQueue *new_queue)
396 gboolean retval = FALSE;
400 if (remove_job_from_queue_locked (old_queue, job)) {
401 add_job_to_async_queue (new_queue, job);
405 g_object_unref (job);
411 move_job (EvJob *job, GQueue *old_queue, GQueue *new_queue)
413 gboolean retval = FALSE;
415 g_mutex_lock (ev_queue_mutex);
418 if (remove_job_from_queue_locked (old_queue, job)) {
419 add_job_to_queue_locked (new_queue, job);
423 g_object_unref (job);
424 g_mutex_unlock (ev_queue_mutex);
430 ev_job_queue_update_job (EvJob *job,
431 EvJobPriority new_priority)
433 gboolean retval = FALSE;
435 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
437 if (EV_JOB (job)->async) {
438 if (EV_IS_JOB_RENDER (job)) {
439 if (new_priority == EV_JOB_PRIORITY_LOW) {
440 retval = move_job_async (job, async_render_queue_high,
441 async_render_queue_low);
442 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
443 retval = move_job_async (job, async_render_queue_low,
444 async_render_queue_high);
447 g_assert_not_reached ();
450 if (EV_IS_JOB_THUMBNAIL (job)) {
451 if (new_priority == EV_JOB_PRIORITY_LOW) {
452 retval = move_job (job, thumbnail_queue_high,
453 thumbnail_queue_low);
454 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
455 retval = move_job (job, thumbnail_queue_low,
456 thumbnail_queue_high);
458 } else if (EV_IS_JOB_RENDER (job)) {
459 if (new_priority == EV_JOB_PRIORITY_LOW) {
460 retval = move_job (job, render_queue_high,
462 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
463 retval = move_job (job, render_queue_low,
467 g_assert_not_reached ();
475 ev_job_queue_remove_job (EvJob *job)
477 gboolean retval = FALSE;
479 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
481 if (EV_JOB (job)->async) {
482 if (EV_IS_JOB_RENDER (job)) {
483 retval = remove_job_from_async_queue (async_render_queue_high, job);
484 retval = retval || remove_job_from_async_queue (async_render_queue_low, job);
486 g_assert_not_reached ();
489 g_mutex_lock (ev_queue_mutex);
491 if (EV_IS_JOB_THUMBNAIL (job)) {
492 retval = remove_job_from_queue_locked (thumbnail_queue_high, job);
493 retval = retval || remove_job_from_queue_locked (thumbnail_queue_low, job);
494 } else if (EV_IS_JOB_RENDER (job)) {
495 retval = remove_job_from_queue_locked (render_queue_high, job);
496 retval = retval || remove_job_from_queue_locked (render_queue_low, job);
497 } else if (EV_IS_JOB_LINKS (job)) {
498 retval = remove_job_from_queue_locked (links_queue, job);
499 } else if (EV_IS_JOB_LOAD (job)) {
500 retval = remove_job_from_queue_locked (load_queue, job);
501 } else if (EV_IS_JOB_SAVE (job)) {
502 retval = remove_job_from_queue_locked (save_queue, job);
503 } else if (EV_IS_JOB_FONTS (job)) {
504 retval = remove_job_from_queue_locked (fonts_queue, job);
505 } else if (EV_IS_JOB_PRINT (job)) {
506 retval = remove_job_from_queue_locked (print_queue, job);
508 g_assert_not_reached ();
511 g_mutex_unlock (ev_queue_mutex);