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 *save_queue = NULL;
17 static GQueue *fonts_queue = NULL;
18 static GQueue *print_queue = NULL;
20 /* Queues used for backends supporting EvAsyncRender interface,
21 they are executed on the main thread */
22 static GQueue *async_render_queue_high = NULL;
23 static GQueue *async_render_queue_low = NULL;
24 static gboolean async_rendering = FALSE;
26 static void ev_job_queue_run_next (void);
29 remove_job_from_queue_locked (GQueue *queue, EvJob *job)
33 list = g_queue_find (queue, job);
35 g_object_unref (G_OBJECT (job));
36 g_queue_delete_link (queue, list);
44 remove_job_from_async_queue (GQueue *queue, EvJob *job)
46 return remove_job_from_queue_locked (queue, job);
50 add_job_to_async_queue (GQueue *queue, EvJob *job)
53 g_queue_push_tail (queue, job);
57 * add_job_to_queue_locked:
58 * @queue: a #GQueue where the #EvJob will be added.
59 * @job: an #EvJob to be added to the specified #GQueue.
61 * Add the #EvJob to the specified #GQueue and woke up the ev_render_thread who
62 * is waiting for render_cond.
65 add_job_to_queue_locked (GQueue *queue,
69 g_queue_push_tail (queue, job);
70 g_cond_broadcast (render_cond);
75 * @job: the object that signal will be reseted.
77 * It does emit the job finished signal and returns %FALSE.
82 notify_finished (GObject *job)
84 ev_job_finished (EV_JOB (job));
91 * @job: the #EvJob that has been handled.
93 * It does finish the job last work and look if there is any more job to be
97 job_finished_cb (EvJob *job)
100 async_rendering = FALSE;
101 ev_job_queue_run_next ();
106 * @job: the #EvJob to be handled.
108 * First, it does check if the job is async and then it does attend it if
109 * possible giving a failed assertion otherwise. If the job isn't async it does
110 * attend it and notify that the job has been finished.
113 handle_job (EvJob *job)
115 g_object_ref (G_OBJECT (job));
117 if (EV_JOB (job)->async) {
118 async_rendering = TRUE;
119 if (EV_IS_JOB_RENDER (job)) {
120 g_signal_connect (job, "finished",
121 G_CALLBACK (job_finished_cb), NULL);
123 g_assert_not_reached ();
127 if (EV_IS_JOB_THUMBNAIL (job))
128 ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job));
129 else if (EV_IS_JOB_LINKS (job))
130 ev_job_links_run (EV_JOB_LINKS (job));
131 else if (EV_IS_JOB_LOAD (job))
132 ev_job_load_run (EV_JOB_LOAD (job));
133 else if (EV_IS_JOB_SAVE (job))
134 ev_job_save_run (EV_JOB_SAVE (job));
135 else if (EV_IS_JOB_RENDER (job))
136 ev_job_render_run (EV_JOB_RENDER (job));
137 else if (EV_IS_JOB_FONTS (job))
138 ev_job_fonts_run (EV_JOB_FONTS (job));
139 else if (EV_IS_JOB_PRINT (job))
140 ev_job_print_run (EV_JOB_PRINT (job));
142 if (!EV_JOB (job)->async) {
143 /* We let the idle own a ref, as we (the queue) are done with the job. */
144 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
145 (GSourceFunc) notify_finished,
152 * search_for_jobs_unlocked:
154 * Check if there is any job at the synchronized queues and return any existing
155 * job in them taking in account the next priority:
157 * render_queue_high >
158 * thumbnail_queue_high >
162 * thumbnail_queue_low >
166 * Returns: an available #EvJob in the queues taking in account stablished queue
170 search_for_jobs_unlocked (void)
174 job = (EvJob *) g_queue_pop_head (render_queue_high);
178 job = (EvJob *) g_queue_pop_head (thumbnail_queue_high);
182 job = (EvJob *) g_queue_pop_head (render_queue_low);
186 job = (EvJob *) g_queue_pop_head (links_queue);
190 job = (EvJob *) g_queue_pop_head (load_queue);
194 job = (EvJob *) g_queue_pop_head (save_queue);
198 job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
202 job = (EvJob *) g_queue_pop_head (fonts_queue);
206 job = (EvJob *) g_queue_pop_head (print_queue);
214 * no_jobs_available_unlocked:
216 * Looks if there is any job at render, links, load, thumbnail. fonts and print
219 * Returns: %TRUE if the render, links, load, thumbnail, fonts and print queues
220 * are empty, %FALSE in other case.
223 no_jobs_available_unlocked (void)
225 return g_queue_is_empty (render_queue_high)
226 && g_queue_is_empty (render_queue_low)
227 && g_queue_is_empty (links_queue)
228 && g_queue_is_empty (load_queue)
229 && g_queue_is_empty (save_queue)
230 && g_queue_is_empty (thumbnail_queue_high)
231 && g_queue_is_empty (thumbnail_queue_low)
232 && g_queue_is_empty (fonts_queue)
233 && g_queue_is_empty (print_queue);
236 /* the thread mainloop function */
239 * @data: data passed to the thread.
241 * The thread mainloop function. It does wait for any available job in synced
242 * queues to handle it.
244 * Returns: the return value of the thread, which will be returned by
248 ev_render_thread (gpointer data)
253 g_mutex_lock (ev_queue_mutex);
254 if (no_jobs_available_unlocked ()) {
255 g_cond_wait (render_cond, ev_queue_mutex);
258 job = search_for_jobs_unlocked ();
259 g_mutex_unlock (ev_queue_mutex);
261 /* Now that we have our job, we handle it */
264 g_object_unref (G_OBJECT (job));
272 * ev_job_queue_run_next:
274 * It does look for any job on the render high priority queue first and after
275 * in the render low priority one, and then it does handle it.
278 ev_job_queue_run_next (void)
282 job = (EvJob *) g_queue_pop_head (async_render_queue_high);
285 job = (EvJob *) g_queue_pop_head (async_render_queue_low);
288 /* Now that we have our job, we handle it */
291 g_object_unref (G_OBJECT (job));
295 /* Public Functions */
299 * Creates a new cond, new mutex, a thread for evince job handling and inits
303 ev_job_queue_init (void)
305 if (!g_thread_supported ()) g_thread_init (NULL);
307 render_cond = g_cond_new ();
308 ev_queue_mutex = g_mutex_new ();
310 links_queue = g_queue_new ();
311 load_queue = g_queue_new ();
312 save_queue = g_queue_new ();
313 render_queue_high = g_queue_new ();
314 render_queue_low = g_queue_new ();
315 async_render_queue_high = g_queue_new ();
316 async_render_queue_low = g_queue_new ();
317 thumbnail_queue_high = g_queue_new ();
318 thumbnail_queue_low = g_queue_new ();
319 fonts_queue = g_queue_new ();
320 print_queue = g_queue_new ();
322 g_thread_create (ev_render_thread, NULL, FALSE, NULL);
327 find_queue (EvJob *job,
328 EvJobPriority priority)
330 if (EV_JOB (job)->async) {
331 if (EV_IS_JOB_RENDER (job)) {
332 if (priority == EV_JOB_PRIORITY_HIGH)
333 return async_render_queue_high;
335 return async_render_queue_low;
338 if (EV_IS_JOB_RENDER (job)) {
339 if (priority == EV_JOB_PRIORITY_HIGH)
340 return render_queue_high;
342 return render_queue_low;
343 } else if (EV_IS_JOB_THUMBNAIL (job)) {
344 if (priority == EV_JOB_PRIORITY_HIGH)
345 return thumbnail_queue_high;
347 return thumbnail_queue_low;
348 } else if (EV_IS_JOB_LOAD (job)) {
349 /* the priority doesn't effect load */
351 } else if (EV_IS_JOB_SAVE (job)) {
352 /* the priority doesn't effect save */
354 } else if (EV_IS_JOB_LINKS (job)) {
355 /* the priority doesn't effect links */
357 } else if (EV_IS_JOB_FONTS (job)) {
358 /* the priority doesn't effect fonts */
360 } else if (EV_IS_JOB_PRINT (job)) {
361 /* the priority doesn't effect print */
366 g_assert_not_reached ();
371 ev_job_queue_add_job (EvJob *job,
372 EvJobPriority priority)
376 g_return_if_fail (EV_IS_JOB (job));
378 queue = find_queue (job, priority);
380 if (!EV_JOB (job)->async) {
381 g_mutex_lock (ev_queue_mutex);
382 add_job_to_queue_locked (queue, job);
383 g_mutex_unlock (ev_queue_mutex);
385 add_job_to_async_queue (queue, job);
386 if (!async_rendering) {
387 ev_job_queue_run_next ();
393 move_job_async (EvJob *job, GQueue *old_queue, GQueue *new_queue)
395 gboolean retval = FALSE;
399 if (remove_job_from_queue_locked (old_queue, job)) {
400 add_job_to_async_queue (new_queue, job);
404 g_object_unref (job);
410 move_job (EvJob *job, GQueue *old_queue, GQueue *new_queue)
412 gboolean retval = FALSE;
414 g_mutex_lock (ev_queue_mutex);
417 if (remove_job_from_queue_locked (old_queue, job)) {
418 add_job_to_queue_locked (new_queue, job);
422 g_object_unref (job);
423 g_mutex_unlock (ev_queue_mutex);
429 ev_job_queue_update_job (EvJob *job,
430 EvJobPriority new_priority)
432 gboolean retval = FALSE;
434 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
436 if (EV_JOB (job)->async) {
437 if (EV_IS_JOB_RENDER (job)) {
438 if (new_priority == EV_JOB_PRIORITY_LOW) {
439 retval = move_job_async (job, async_render_queue_high,
440 async_render_queue_low);
441 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
442 retval = move_job_async (job, async_render_queue_low,
443 async_render_queue_high);
446 g_assert_not_reached ();
449 if (EV_IS_JOB_THUMBNAIL (job)) {
450 if (new_priority == EV_JOB_PRIORITY_LOW) {
451 retval = move_job (job, thumbnail_queue_high,
452 thumbnail_queue_low);
453 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
454 retval = move_job (job, thumbnail_queue_low,
455 thumbnail_queue_high);
457 } else if (EV_IS_JOB_RENDER (job)) {
458 if (new_priority == EV_JOB_PRIORITY_LOW) {
459 retval = move_job (job, render_queue_high,
461 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
462 retval = move_job (job, render_queue_low,
466 g_assert_not_reached ();
474 ev_job_queue_remove_job (EvJob *job)
476 gboolean retval = FALSE;
478 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
480 if (EV_JOB (job)->async) {
481 if (EV_IS_JOB_RENDER (job)) {
482 retval = remove_job_from_async_queue (async_render_queue_high, job);
483 retval = retval || remove_job_from_async_queue (async_render_queue_low, job);
485 g_assert_not_reached ();
488 g_mutex_lock (ev_queue_mutex);
490 if (EV_IS_JOB_THUMBNAIL (job)) {
491 retval = remove_job_from_queue_locked (thumbnail_queue_high, job);
492 retval = retval || remove_job_from_queue_locked (thumbnail_queue_low, job);
493 } else if (EV_IS_JOB_RENDER (job)) {
494 retval = remove_job_from_queue_locked (render_queue_high, job);
495 retval = retval || remove_job_from_queue_locked (render_queue_low, job);
496 } else if (EV_IS_JOB_LINKS (job)) {
497 retval = remove_job_from_queue_locked (links_queue, job);
498 } else if (EV_IS_JOB_LOAD (job)) {
499 retval = remove_job_from_queue_locked (load_queue, job);
500 } else if (EV_IS_JOB_SAVE (job)) {
501 retval = remove_job_from_queue_locked (save_queue, job);
502 } else if (EV_IS_JOB_FONTS (job)) {
503 retval = remove_job_from_queue_locked (fonts_queue, job);
504 } else if (EV_IS_JOB_PRINT (job)) {
505 retval = remove_job_from_queue_locked (print_queue, job);
507 g_assert_not_reached ();
510 g_mutex_unlock (ev_queue_mutex);