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;
16 /* Queues used for backends supporting EvAsyncRender interface,
17 they are executed on the main thread */
18 static GQueue *async_render_queue_high = NULL;
19 static GQueue *async_render_queue_low = NULL;
20 static gboolean async_rendering = FALSE;
22 static void ev_job_queue_run_next (void);
25 remove_job_from_queue_locked (GQueue *queue, EvJob *job)
29 list = g_queue_find (queue, job);
31 g_object_unref (G_OBJECT (job));
32 g_queue_delete_link (queue, list);
40 remove_job_from_async_queue (GQueue *queue, EvJob *job)
42 return remove_job_from_queue_locked (queue, job);
46 add_job_to_async_queue (GQueue *queue, EvJob *job)
49 g_queue_push_tail (queue, job);
53 add_job_to_queue_locked (GQueue *queue,
57 g_queue_push_tail (queue, job);
58 g_cond_broadcast (render_cond);
62 notify_finished (GObject *job)
64 ev_job_finished (EV_JOB (job));
70 job_finished_cb (EvJob *job)
73 async_rendering = FALSE;
74 ev_job_queue_run_next ();
78 handle_job (EvJob *job)
80 g_object_ref (G_OBJECT (job));
82 if (EV_JOB (job)->async) {
83 async_rendering = TRUE;
84 if (EV_IS_JOB_RENDER (job)) {
85 g_signal_connect (job, "finished",
86 G_CALLBACK (job_finished_cb), NULL);
88 g_assert_not_reached ();
92 if (EV_IS_JOB_THUMBNAIL (job))
93 ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job));
94 else if (EV_IS_JOB_LINKS (job))
95 ev_job_links_run (EV_JOB_LINKS (job));
96 else if (EV_IS_JOB_RENDER (job))
97 ev_job_render_run (EV_JOB_RENDER (job));
99 if (!EV_JOB (job)->async) {
100 /* We let the idle own a ref, as we (the queue) are done with the job. */
101 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
102 (GSourceFunc) notify_finished,
109 search_for_jobs_unlocked (void)
113 job = (EvJob *) g_queue_pop_head (render_queue_high);
117 job = (EvJob *) g_queue_pop_head (thumbnail_queue_high);
121 job = (EvJob *) g_queue_pop_head (render_queue_low);
125 job = (EvJob *) g_queue_pop_head (links_queue);
129 job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
137 no_jobs_available_unlocked (void)
139 return g_queue_is_empty (render_queue_high)
140 && g_queue_is_empty (render_queue_low)
141 && g_queue_is_empty (links_queue)
142 && g_queue_is_empty (thumbnail_queue_high)
143 && g_queue_is_empty (thumbnail_queue_low);
146 /* the thread mainloop function */
148 ev_render_thread (gpointer data)
153 g_mutex_lock (ev_queue_mutex);
154 if (no_jobs_available_unlocked ()) {
155 g_cond_wait (render_cond, ev_queue_mutex);
158 job = search_for_jobs_unlocked ();
159 g_mutex_unlock (ev_queue_mutex);
161 /* Now that we have our job, we handle it */
164 g_object_unref (G_OBJECT (job));
172 ev_job_queue_run_next (void)
176 job = (EvJob *) g_queue_pop_head (async_render_queue_high);
179 job = (EvJob *) g_queue_pop_head (async_render_queue_low);
182 /* Now that we have our job, we handle it */
185 g_object_unref (G_OBJECT (job));
189 /* Public Functions */
191 ev_job_queue_init (void)
193 if (!g_thread_supported ()) g_thread_init (NULL);
195 render_cond = g_cond_new ();
196 ev_queue_mutex = g_mutex_new ();
198 links_queue = g_queue_new ();
199 render_queue_high = g_queue_new ();
200 render_queue_low = g_queue_new ();
201 async_render_queue_high = g_queue_new ();
202 async_render_queue_low = g_queue_new ();
203 thumbnail_queue_high = g_queue_new ();
204 thumbnail_queue_low = g_queue_new ();
206 g_thread_create (ev_render_thread, NULL, FALSE, NULL);
211 find_queue (EvJob *job,
212 EvJobPriority priority)
214 if (EV_JOB (job)->async) {
215 if (EV_IS_JOB_RENDER (job)) {
216 if (priority == EV_JOB_PRIORITY_HIGH)
217 return async_render_queue_high;
219 return async_render_queue_low;
222 if (EV_IS_JOB_RENDER (job)) {
223 if (priority == EV_JOB_PRIORITY_HIGH)
224 return render_queue_high;
226 return render_queue_low;
227 } else if (EV_IS_JOB_THUMBNAIL (job)) {
228 if (priority == EV_JOB_PRIORITY_HIGH)
229 return thumbnail_queue_high;
231 return thumbnail_queue_low;
232 } else if (EV_IS_JOB_LINKS (job)) {
233 /* the priority doesn't effect links */
238 g_assert_not_reached ();
243 ev_job_queue_add_job (EvJob *job,
244 EvJobPriority priority)
248 g_return_if_fail (EV_IS_JOB (job));
250 queue = find_queue (job, priority);
252 if (!EV_JOB (job)->async) {
253 g_mutex_lock (ev_queue_mutex);
254 add_job_to_queue_locked (queue, job);
255 g_mutex_unlock (ev_queue_mutex);
257 add_job_to_async_queue (queue, job);
258 if (!async_rendering) {
259 ev_job_queue_run_next ();
265 move_job_async (EvJob *job, GQueue *old_queue, GQueue *new_queue)
267 gboolean retval = FALSE;
271 if (remove_job_from_queue_locked (old_queue, job)) {
272 add_job_to_async_queue (new_queue, job);
276 g_object_unref (job);
282 move_job (EvJob *job, GQueue *old_queue, GQueue *new_queue)
284 gboolean retval = FALSE;
286 g_mutex_lock (ev_queue_mutex);
289 if (remove_job_from_queue_locked (old_queue, job)) {
290 add_job_to_queue_locked (new_queue, job);
294 g_object_unref (job);
295 g_mutex_unlock (ev_queue_mutex);
301 ev_job_queue_update_job (EvJob *job,
302 EvJobPriority new_priority)
304 gboolean retval = FALSE;
306 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
308 if (EV_JOB (job)->async) {
309 if (EV_IS_JOB_RENDER (job)) {
310 if (new_priority == EV_JOB_PRIORITY_LOW) {
311 retval = move_job_async (job, async_render_queue_high,
312 async_render_queue_low);
313 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
314 retval = move_job_async (job, async_render_queue_low,
315 async_render_queue_high);
318 g_assert_not_reached ();
321 if (EV_IS_JOB_THUMBNAIL (job)) {
322 if (new_priority == EV_JOB_PRIORITY_LOW) {
323 retval = move_job (job, thumbnail_queue_high,
324 thumbnail_queue_low);
325 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
326 retval = move_job (job, thumbnail_queue_low,
327 thumbnail_queue_high);
329 } else if (EV_IS_JOB_RENDER (job)) {
330 if (new_priority == EV_JOB_PRIORITY_LOW) {
331 retval = move_job (job, render_queue_high,
333 } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
334 retval = move_job (job, render_queue_low,
338 g_assert_not_reached ();
346 ev_job_queue_remove_job (EvJob *job)
348 gboolean retval = FALSE;
350 g_return_val_if_fail (EV_IS_JOB (job), FALSE);
352 if (EV_JOB (job)->async) {
353 if (EV_IS_JOB_RENDER (job)) {
354 retval = remove_job_from_async_queue (async_render_queue_high, job);
355 retval = retval || remove_job_from_async_queue (async_render_queue_low, job);
357 g_assert_not_reached ();
360 g_mutex_lock (ev_queue_mutex);
362 if (EV_IS_JOB_THUMBNAIL (job)) {
363 retval = remove_job_from_queue_locked (thumbnail_queue_high, job);
364 retval = retval || remove_job_from_queue_locked (thumbnail_queue_low, job);
365 } else if (EV_IS_JOB_RENDER (job)) {
366 retval = remove_job_from_queue_locked (render_queue_high, job);
367 retval = retval || remove_job_from_queue_locked (render_queue_low, job);
368 } else if (EV_IS_JOB_LINKS (job)) {
369 retval = remove_job_from_queue_locked (links_queue, job);
371 g_assert_not_reached ();
374 g_mutex_unlock (ev_queue_mutex);