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 *xfer_queue = NULL;
18 /* Queues used for backends supporting EvAsyncRender interface,
19 they are executed on the main thread */
20 static GQueue *async_render_queue_high = NULL;
21 static GQueue *async_render_queue_low = NULL;
22 static gboolean async_rendering = FALSE;
24 static void ev_job_queue_run_next (void);
27 remove_job_from_queue_locked (GQueue *queue, EvJob *job)
31 list = g_queue_find (queue, job);
33 g_object_unref (G_OBJECT (job));
34 g_queue_delete_link (queue, list);
42 remove_job_from_async_queue (GQueue *queue, EvJob *job)
44 return remove_job_from_queue_locked (queue, job);
48 add_job_to_async_queue (GQueue *queue, EvJob *job)
51 g_queue_push_tail (queue, job);
55 add_job_to_queue_locked (GQueue *queue,
59 g_queue_push_tail (queue, job);
60 g_cond_broadcast (render_cond);
64 notify_finished (GObject *job)
66 ev_job_finished (EV_JOB (job));
72 job_finished_cb (EvJob *job)
75 async_rendering = FALSE;
76 ev_job_queue_run_next ();
80 handle_job (EvJob *job)
82 g_object_ref (G_OBJECT (job));
84 if (EV_JOB (job)->async) {
85 async_rendering = TRUE;
86 if (EV_IS_JOB_RENDER (job)) {
87 g_signal_connect (job, "finished",
88 G_CALLBACK (job_finished_cb), NULL);
90 g_assert_not_reached ();
94 if (EV_IS_JOB_THUMBNAIL (job))
95 ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job));
96 else if (EV_IS_JOB_LINKS (job))
97 ev_job_links_run (EV_JOB_LINKS (job));
98 else if (EV_IS_JOB_LOAD (job))
99 ev_job_load_run (EV_JOB_LOAD (job));
100 else if (EV_IS_JOB_XFER (job))
101 ev_job_xfer_run (EV_JOB_XFER (job));
102 else if (EV_IS_JOB_RENDER (job))
103 ev_job_render_run (EV_JOB_RENDER (job));
105 if (!EV_JOB (job)->async) {
106 /* We let the idle own a ref, as we (the queue) are done with the job. */
107 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
108 (GSourceFunc) notify_finished,
115 search_for_jobs_unlocked (void)
119 job = (EvJob *) g_queue_pop_head (render_queue_high);
123 job = (EvJob *) g_queue_pop_head (thumbnail_queue_high);
127 job = (EvJob *) g_queue_pop_head (render_queue_low);
131 job = (EvJob *) g_queue_pop_head (links_queue);
135 job = (EvJob *) g_queue_pop_head (load_queue);
139 job = (EvJob *) g_queue_pop_head (xfer_queue);
143 job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
151 no_jobs_available_unlocked (void)
153 return g_queue_is_empty (render_queue_high)
154 && g_queue_is_empty (render_queue_low)
155 && g_queue_is_empty (links_queue)
156 && g_queue_is_empty (load_queue)
157 && g_queue_is_empty (xfer_queue)
158 && g_queue_is_empty (thumbnail_queue_high)
159 && g_queue_is_empty (thumbnail_queue_low);
162 /* the thread mainloop function */
164 ev_render_thread (gpointer data)
169 g_mutex_lock (ev_queue_mutex);
170 if (no_jobs_available_unlocked ()) {
171 g_cond_wait (render_cond, ev_queue_mutex);
174 job = search_for_jobs_unlocked ();
175 g_mutex_unlock (ev_queue_mutex);
177 /* Now that we have our job, we handle it */
180 g_object_unref (G_OBJECT (job));
188 ev_job_queue_run_next (void)
192 job = (EvJob *) g_queue_pop_head (async_render_queue_high);
195 job = (EvJob *) g_queue_pop_head (async_render_queue_low);
198 /* Now that we have our job, we handle it */
201 g_object_unref (G_OBJECT (job));
205 /* Public Functions */
207 ev_job_queue_init (void)
209 if (!g_thread_supported ()) g_thread_init (NULL);
211 render_cond = g_cond_new ();
212 ev_queue_mutex = g_mutex_new ();
214 links_queue = g_queue_new ();
215 load_queue = g_queue_new ();
216 xfer_queue = g_queue_new ();
217 render_queue_high = g_queue_new ();
218 render_queue_low = g_queue_new ();
219 async_render_queue_high = g_queue_new ();
220 async_render_queue_low = g_queue_new ();
221 thumbnail_queue_high = g_queue_new ();
222 thumbnail_queue_low = g_queue_new ();
224 g_thread_create (ev_render_thread, NULL, FALSE, NULL);
229 find_queue (EvJob *job,
230 EvJobPriority priority)
232 if (EV_JOB (job)->async) {
233 if (EV_IS_JOB_RENDER (job)) {
234 if (priority == EV_JOB_PRIORITY_HIGH)
235 return async_render_queue_high;
237 return async_render_queue_low;
240 if (EV_IS_JOB_RENDER (job)) {
241 if (priority == EV_JOB_PRIORITY_HIGH)
242 return render_queue_high;
244 return render_queue_low;
245 } else if (EV_IS_JOB_THUMBNAIL (job)) {
246 if (priority == EV_JOB_PRIORITY_HIGH)
247 return thumbnail_queue_high;
249 return thumbnail_queue_low;
250 } else if (EV_IS_JOB_LOAD (job)) {
251 /* the priority doesn't effect load */
253 } else if (EV_IS_JOB_XFER (job)) {
254 /* the priority doesn't effect xfer */
256 } else if (EV_IS_JOB_LINKS (job)) {
257 /* the priority doesn't effect links */
262 g_assert_not_reached ();
267 ev_job_queue_add_job (EvJob *job,
268 EvJobPriority priority)
272 g_return_if_fail (EV_IS_JOB (job));
274 queue = find_queue (job, priority);
276 if (!EV_JOB (job)->async) {
277 g_mutex_lock (ev_queue_mutex);
278 add_job_to_queue_locked (queue, job);
279 g_mutex_unlock (ev_queue_mutex);
281 add_job_to_async_queue (queue, job);
282 if (!async_rendering) {
283 ev_job_queue_run_next ();
289 move_job_async (EvJob *job, GQueue *old_queue, GQueue *new_queue)
291 gboolean retval = FALSE;
295 if (remove_job_from_queue_locked (old_queue, job)) {
296 add_job_to_async_queue (new_queue, job);
300 g_object_unref (job);
306 move_job (EvJob *job, GQueue *old_queue, GQueue *new_queue)
308 gboolean retval = FALSE;
310 g_mutex_lock (ev_queue_mutex);
313 if (remove_job_from_queue_locked (old_queue, job)) {
314 add_job_to_queue_locked (new_queue, job);
318 g_object_unref (job);
319 g_mutex_unlock (ev_queue_mutex);
325 ev_job_queue_update_job (EvJob *job,
326 EvJobPriority new_priority)
328 gboolean retval = FALSE;
330 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
332 if (EV_JOB (job)->async) {
333 if (EV_IS_JOB_RENDER (job)) {
334 if (new_priority == EV_JOB_PRIORITY_LOW) {
335 retval = move_job_async (job, async_render_queue_high,
336 async_render_queue_low);
337 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
338 retval = move_job_async (job, async_render_queue_low,
339 async_render_queue_high);
342 g_assert_not_reached ();
345 if (EV_IS_JOB_THUMBNAIL (job)) {
346 if (new_priority == EV_JOB_PRIORITY_LOW) {
347 retval = move_job (job, thumbnail_queue_high,
348 thumbnail_queue_low);
349 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
350 retval = move_job (job, thumbnail_queue_low,
351 thumbnail_queue_high);
353 } else if (EV_IS_JOB_RENDER (job)) {
354 if (new_priority == EV_JOB_PRIORITY_LOW) {
355 retval = move_job (job, render_queue_high,
357 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
358 retval = move_job (job, render_queue_low,
362 g_assert_not_reached ();
370 ev_job_queue_remove_job (EvJob *job)
372 gboolean retval = FALSE;
374 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
376 if (EV_JOB (job)->async) {
377 if (EV_IS_JOB_RENDER (job)) {
378 retval = remove_job_from_async_queue (async_render_queue_high, job);
379 retval = retval || remove_job_from_async_queue (async_render_queue_low, job);
381 g_assert_not_reached ();
384 g_mutex_lock (ev_queue_mutex);
386 if (EV_IS_JOB_THUMBNAIL (job)) {
387 retval = remove_job_from_queue_locked (thumbnail_queue_high, job);
388 retval = retval || remove_job_from_queue_locked (thumbnail_queue_low, job);
389 } else if (EV_IS_JOB_RENDER (job)) {
390 retval = remove_job_from_queue_locked (render_queue_high, job);
391 retval = retval || remove_job_from_queue_locked (render_queue_low, job);
392 } else if (EV_IS_JOB_LINKS (job)) {
393 retval = remove_job_from_queue_locked (links_queue, job);
394 } else if (EV_IS_JOB_LOAD (job)) {
395 retval = remove_job_from_queue_locked (load_queue, job);
396 } else if (EV_IS_JOB_XFER (job)) {
397 retval = remove_job_from_queue_locked (xfer_queue, job);
399 g_assert_not_reached ();
402 g_mutex_unlock (ev_queue_mutex);