1 #include "ev-job-queue.h"
3 /* Like glib calling convention, all functions with _locked in their name assume
4 * that we've already locked the doc mutex and can freely and safely access
7 GCond *render_cond = NULL;
8 GMutex *ev_queue_mutex = NULL;
10 static GQueue *links_queue = NULL;
11 static GQueue *render_queue_high = NULL;
12 static GQueue *render_queue_low = NULL;
13 static GQueue *thumbnail_queue_high = NULL;
14 static GQueue *thumbnail_queue_low = NULL;
15 static GQueue *load_queue = NULL;
16 static GQueue *fonts_queue = NULL;
17 static GQueue *print_queue = NULL;
19 /* Queues used for backends supporting EvAsyncRender interface,
20 they are executed on the main thread */
21 static GQueue *async_render_queue_high = NULL;
22 static GQueue *async_render_queue_low = NULL;
23 static gboolean async_rendering = FALSE;
25 static void ev_job_queue_run_next (void);
28 remove_job_from_queue_locked (GQueue *queue, EvJob *job)
32 list = g_queue_find (queue, job);
34 g_object_unref (G_OBJECT (job));
35 g_queue_delete_link (queue, list);
43 remove_job_from_async_queue (GQueue *queue, EvJob *job)
45 return remove_job_from_queue_locked (queue, job);
49 add_job_to_async_queue (GQueue *queue, EvJob *job)
52 g_queue_push_tail (queue, job);
56 * add_job_to_queue_locked:
57 * @queue: a #GQueue where the #EvJob will be added.
58 * @job: an #EvJob to be added to the specified #GQueue.
60 * Add the #EvJob to the specified #GQueue and woke up the ev_render_thread who
61 * is waiting for render_cond.
64 add_job_to_queue_locked (GQueue *queue,
68 g_queue_push_tail (queue, job);
69 g_cond_broadcast (render_cond);
74 * @job: the object that signal will be reseted.
76 * It does emit the job finished signal and returns %FALSE.
81 notify_finished (GObject *job)
83 ev_job_finished (EV_JOB (job));
90 * @job: the #EvJob that has been handled.
92 * It does finish the job last work and look if there is any more job to be
96 job_finished_cb (EvJob *job)
99 async_rendering = FALSE;
100 ev_job_queue_run_next ();
105 * @job: the #EvJob to be handled.
107 * First, it does check if the job is async and then it does attend it if
108 * possible giving a failed assertion otherwise. If the job isn't async it does
109 * attend it and notify that the job has been finished.
112 handle_job (EvJob *job)
114 g_object_ref (G_OBJECT (job));
116 if (EV_JOB (job)->async) {
117 async_rendering = TRUE;
118 if (EV_IS_JOB_RENDER (job)) {
119 g_signal_connect (job, "finished",
120 G_CALLBACK (job_finished_cb), NULL);
122 g_assert_not_reached ();
126 if (EV_IS_JOB_THUMBNAIL (job))
127 ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job));
128 else if (EV_IS_JOB_LINKS (job))
129 ev_job_links_run (EV_JOB_LINKS (job));
130 else if (EV_IS_JOB_LOAD (job))
131 ev_job_load_run (EV_JOB_LOAD (job));
132 else if (EV_IS_JOB_RENDER (job))
133 ev_job_render_run (EV_JOB_RENDER (job));
134 else if (EV_IS_JOB_FONTS (job))
135 ev_job_fonts_run (EV_JOB_FONTS (job));
136 else if (EV_IS_JOB_PRINT (job))
137 ev_job_print_run (EV_JOB_PRINT (job));
139 if (!EV_JOB (job)->async) {
140 /* We let the idle own a ref, as we (the queue) are done with the job. */
141 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
142 (GSourceFunc) notify_finished,
149 * search_for_jobs_unlocked:
151 * Check if there is any job at the synchronized queues and return any existing
152 * job in them taking in account the next priority:
154 * render_queue_high >
155 * thumbnail_queue_high >
159 * thumbnail_queue_low >
163 * Returns: an available #EvJob in the queues taking in account stablished queue
167 search_for_jobs_unlocked (void)
171 job = (EvJob *) g_queue_pop_head (render_queue_high);
175 job = (EvJob *) g_queue_pop_head (thumbnail_queue_high);
179 job = (EvJob *) g_queue_pop_head (render_queue_low);
183 job = (EvJob *) g_queue_pop_head (links_queue);
187 job = (EvJob *) g_queue_pop_head (load_queue);
191 job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
195 job = (EvJob *) g_queue_pop_head (fonts_queue);
199 job = (EvJob *) g_queue_pop_head (print_queue);
207 * no_jobs_available_unlocked:
209 * Looks if there is any job at render, links, load, thumbnail. fonts and print
212 * Returns: %TRUE if the render, links, load, thumbnail, fonts and print queues
213 * are empty, %FALSE in other case.
216 no_jobs_available_unlocked (void)
218 return g_queue_is_empty (render_queue_high)
219 && g_queue_is_empty (render_queue_low)
220 && g_queue_is_empty (links_queue)
221 && g_queue_is_empty (load_queue)
222 && g_queue_is_empty (thumbnail_queue_high)
223 && g_queue_is_empty (thumbnail_queue_low)
224 && g_queue_is_empty (fonts_queue)
225 && g_queue_is_empty (print_queue);
228 /* the thread mainloop function */
231 * @data: data passed to the thread.
233 * The thread mainloop function. It does wait for any available job in synced
234 * queues to handle it.
236 * Returns: the return value of the thread, which will be returned by
240 ev_render_thread (gpointer data)
245 g_mutex_lock (ev_queue_mutex);
246 if (no_jobs_available_unlocked ()) {
247 g_cond_wait (render_cond, ev_queue_mutex);
250 job = search_for_jobs_unlocked ();
251 g_mutex_unlock (ev_queue_mutex);
253 /* Now that we have our job, we handle it */
256 g_object_unref (G_OBJECT (job));
264 * ev_job_queue_run_next:
266 * It does look for any job on the render high priority queue first and after
267 * in the render low priority one, and then it does handle it.
270 ev_job_queue_run_next (void)
274 job = (EvJob *) g_queue_pop_head (async_render_queue_high);
277 job = (EvJob *) g_queue_pop_head (async_render_queue_low);
280 /* Now that we have our job, we handle it */
283 g_object_unref (G_OBJECT (job));
287 /* Public Functions */
291 * Creates a new cond, new mutex, a thread for evince job handling and inits
295 ev_job_queue_init (void)
297 if (!g_thread_supported ()) g_thread_init (NULL);
299 render_cond = g_cond_new ();
300 ev_queue_mutex = g_mutex_new ();
302 links_queue = g_queue_new ();
303 load_queue = g_queue_new ();
304 render_queue_high = g_queue_new ();
305 render_queue_low = g_queue_new ();
306 async_render_queue_high = g_queue_new ();
307 async_render_queue_low = g_queue_new ();
308 thumbnail_queue_high = g_queue_new ();
309 thumbnail_queue_low = g_queue_new ();
310 fonts_queue = g_queue_new ();
311 print_queue = g_queue_new ();
313 g_thread_create (ev_render_thread, NULL, FALSE, NULL);
318 find_queue (EvJob *job,
319 EvJobPriority priority)
321 if (EV_JOB (job)->async) {
322 if (EV_IS_JOB_RENDER (job)) {
323 if (priority == EV_JOB_PRIORITY_HIGH)
324 return async_render_queue_high;
326 return async_render_queue_low;
329 if (EV_IS_JOB_RENDER (job)) {
330 if (priority == EV_JOB_PRIORITY_HIGH)
331 return render_queue_high;
333 return render_queue_low;
334 } else if (EV_IS_JOB_THUMBNAIL (job)) {
335 if (priority == EV_JOB_PRIORITY_HIGH)
336 return thumbnail_queue_high;
338 return thumbnail_queue_low;
339 } else if (EV_IS_JOB_LOAD (job)) {
340 /* the priority doesn't effect load */
342 } else if (EV_IS_JOB_LINKS (job)) {
343 /* the priority doesn't effect links */
345 } else if (EV_IS_JOB_FONTS (job)) {
346 /* the priority doesn't effect fonts */
348 } else if (EV_IS_JOB_PRINT (job)) {
349 /* the priority doesn't effect print */
354 g_assert_not_reached ();
359 ev_job_queue_add_job (EvJob *job,
360 EvJobPriority priority)
364 g_return_if_fail (EV_IS_JOB (job));
366 queue = find_queue (job, priority);
368 if (!EV_JOB (job)->async) {
369 g_mutex_lock (ev_queue_mutex);
370 add_job_to_queue_locked (queue, job);
371 g_mutex_unlock (ev_queue_mutex);
373 add_job_to_async_queue (queue, job);
374 if (!async_rendering) {
375 ev_job_queue_run_next ();
381 move_job_async (EvJob *job, GQueue *old_queue, GQueue *new_queue)
383 gboolean retval = FALSE;
387 if (remove_job_from_queue_locked (old_queue, job)) {
388 add_job_to_async_queue (new_queue, job);
392 g_object_unref (job);
398 move_job (EvJob *job, GQueue *old_queue, GQueue *new_queue)
400 gboolean retval = FALSE;
402 g_mutex_lock (ev_queue_mutex);
405 if (remove_job_from_queue_locked (old_queue, job)) {
406 add_job_to_queue_locked (new_queue, job);
410 g_object_unref (job);
411 g_mutex_unlock (ev_queue_mutex);
417 ev_job_queue_update_job (EvJob *job,
418 EvJobPriority new_priority)
420 gboolean retval = FALSE;
422 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
424 if (EV_JOB (job)->async) {
425 if (EV_IS_JOB_RENDER (job)) {
426 if (new_priority == EV_JOB_PRIORITY_LOW) {
427 retval = move_job_async (job, async_render_queue_high,
428 async_render_queue_low);
429 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
430 retval = move_job_async (job, async_render_queue_low,
431 async_render_queue_high);
434 g_assert_not_reached ();
437 if (EV_IS_JOB_THUMBNAIL (job)) {
438 if (new_priority == EV_JOB_PRIORITY_LOW) {
439 retval = move_job (job, thumbnail_queue_high,
440 thumbnail_queue_low);
441 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
442 retval = move_job (job, thumbnail_queue_low,
443 thumbnail_queue_high);
445 } else if (EV_IS_JOB_RENDER (job)) {
446 if (new_priority == EV_JOB_PRIORITY_LOW) {
447 retval = move_job (job, render_queue_high,
449 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
450 retval = move_job (job, render_queue_low,
454 g_assert_not_reached ();
462 ev_job_queue_remove_job (EvJob *job)
464 gboolean retval = FALSE;
466 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
468 if (EV_JOB (job)->async) {
469 if (EV_IS_JOB_RENDER (job)) {
470 retval = remove_job_from_async_queue (async_render_queue_high, job);
471 retval = retval || remove_job_from_async_queue (async_render_queue_low, job);
473 g_assert_not_reached ();
476 g_mutex_lock (ev_queue_mutex);
478 if (EV_IS_JOB_THUMBNAIL (job)) {
479 retval = remove_job_from_queue_locked (thumbnail_queue_high, job);
480 retval = retval || remove_job_from_queue_locked (thumbnail_queue_low, job);
481 } else if (EV_IS_JOB_RENDER (job)) {
482 retval = remove_job_from_queue_locked (render_queue_high, job);
483 retval = retval || remove_job_from_queue_locked (render_queue_low, job);
484 } else if (EV_IS_JOB_LINKS (job)) {
485 retval = remove_job_from_queue_locked (links_queue, job);
486 } else if (EV_IS_JOB_LOAD (job)) {
487 retval = remove_job_from_queue_locked (load_queue, job);
488 } else if (EV_IS_JOB_FONTS (job)) {
489 retval = remove_job_from_queue_locked (fonts_queue, job);
490 } else if (EV_IS_JOB_PRINT (job)) {
491 retval = remove_job_from_queue_locked (print_queue, job);
493 g_assert_not_reached ();
496 g_mutex_unlock (ev_queue_mutex);