2 * this file is part of evince, a gnome document viewer
4 * Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
6 * Evince is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Evince is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "ev-job-scheduler.h"
24 typedef struct _EvSchedulerJob {
26 EvJobPriority priority;
30 G_LOCK_DEFINE_STATIC(job_list);
31 static GSList *job_list = NULL;
33 static gpointer ev_job_thread_proxy (gpointer data);
34 static void ev_scheduler_thread_job_cancelled (EvSchedulerJob *job,
35 GCancellable *cancellable);
38 static GQueue queue_urgent = G_QUEUE_INIT;
39 static GQueue queue_high = G_QUEUE_INIT;
40 static GQueue queue_low = G_QUEUE_INIT;
41 static GQueue queue_none = G_QUEUE_INIT;
43 static GCond *job_queue_cond = NULL;
44 static GMutex *job_queue_mutex = NULL;
45 static GQueue *job_queue[EV_JOB_N_PRIORITIES] = {
53 ev_job_queue_push (EvSchedulerJob *job,
54 EvJobPriority priority)
56 ev_debug_message (DEBUG_JOBS, "%s priority %d", EV_GET_TYPE_NAME (job->job), priority);
58 g_mutex_lock (job_queue_mutex);
60 g_queue_push_tail (job_queue[priority], job);
61 g_cond_broadcast (job_queue_cond);
63 g_mutex_unlock (job_queue_mutex);
66 static EvSchedulerJob *
67 ev_job_queue_get_next_unlocked (void)
70 EvSchedulerJob *job = NULL;
72 for (i = EV_JOB_PRIORITY_URGENT; i < EV_JOB_N_PRIORITIES; i++) {
73 job = (EvSchedulerJob *) g_queue_pop_head (job_queue[i]);
78 ev_debug_message (DEBUG_JOBS, "%s", job ? EV_GET_TYPE_NAME (job->job) : "No jobs in queue");
84 ev_job_scheduler_init (gpointer data)
86 job_queue_cond = g_cond_new ();
87 job_queue_mutex = g_mutex_new ();
88 g_thread_create (ev_job_thread_proxy, NULL, FALSE, NULL);
94 ev_scheduler_job_list_add (EvSchedulerJob *job)
96 ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job));
100 job_list = g_slist_prepend (job_list, job);
101 job->job_link = job_list;
107 ev_scheduler_job_list_remove (EvSchedulerJob *job)
109 ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job));
113 job_list = g_slist_delete_link (job_list, job->job_link);
119 ev_scheduler_job_free (EvSchedulerJob *job)
124 g_object_unref (job->job);
129 ev_scheduler_job_destroy (EvSchedulerJob *job)
131 ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job));
133 if (job->job->run_mode == EV_JOB_RUN_MAIN_LOOP) {
134 g_signal_handlers_disconnect_by_func (job->job,
135 G_CALLBACK (ev_scheduler_job_destroy),
138 g_signal_handlers_disconnect_by_func (job->job->cancellable,
139 G_CALLBACK (ev_scheduler_thread_job_cancelled),
143 ev_scheduler_job_list_remove (job);
144 ev_scheduler_job_free (job);
148 ev_scheduler_thread_job_cancelled (EvSchedulerJob *job,
149 GCancellable *cancellable)
153 ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job));
155 g_mutex_lock (job_queue_mutex);
157 /* If the job is not still running,
158 * remove it from the job queue and job list.
159 * If the job is currently running, it will be
160 * destroyed as soon as it finishes.
162 list = g_queue_find (job_queue[job->priority], job);
164 g_queue_delete_link (job_queue[job->priority], list);
165 g_mutex_unlock (job_queue_mutex);
166 ev_scheduler_job_destroy (job);
168 g_mutex_unlock (job_queue_mutex);
173 ev_job_thread (EvJob *job)
177 ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job));
180 if (g_cancellable_is_cancelled (job->cancellable))
183 result = ev_job_run (job);
188 ev_job_idle (EvJob *job)
190 ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job));
192 if (g_cancellable_is_cancelled (job->cancellable))
195 return ev_job_run (job);
199 ev_job_thread_proxy (gpointer data)
204 g_mutex_lock (job_queue_mutex);
205 job = ev_job_queue_get_next_unlocked ();
207 g_cond_wait (job_queue_cond, job_queue_mutex);
208 g_mutex_unlock (job_queue_mutex);
211 g_mutex_unlock (job_queue_mutex);
213 ev_job_thread (job->job);
214 ev_scheduler_job_destroy (job);
221 ev_job_scheduler_push_job (EvJob *job,
222 EvJobPriority priority)
224 static GOnce once_init = G_ONCE_INIT;
225 EvSchedulerJob *s_job;
227 g_once (&once_init, ev_job_scheduler_init, NULL);
229 ev_debug_message (DEBUG_JOBS, "%s pirority %d", EV_GET_TYPE_NAME (job), priority);
231 s_job = g_new0 (EvSchedulerJob, 1);
232 s_job->job = g_object_ref (job);
233 s_job->priority = priority;
235 ev_scheduler_job_list_add (s_job);
237 switch (ev_job_get_run_mode (job)) {
238 case EV_JOB_RUN_THREAD:
239 g_signal_connect_swapped (job->cancellable, "cancelled",
240 G_CALLBACK (ev_scheduler_thread_job_cancelled),
242 ev_job_queue_push (s_job, priority);
244 case EV_JOB_RUN_MAIN_LOOP:
245 g_signal_connect_swapped (job, "finished",
246 G_CALLBACK (ev_scheduler_job_destroy),
248 g_signal_connect_swapped (job, "cancelled",
249 G_CALLBACK (ev_scheduler_job_destroy),
251 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
252 (GSourceFunc)ev_job_idle,
254 (GDestroyNotify)g_object_unref);
257 g_assert_not_reached ();
262 ev_job_scheduler_update_job (EvJob *job,
263 EvJobPriority priority)
266 EvSchedulerJob *s_job = NULL;
267 gboolean need_resort = FALSE;
269 /* Main loop jobs are scheduled inmediately */
270 if (ev_job_get_run_mode (job) == EV_JOB_RUN_MAIN_LOOP)
273 ev_debug_message (DEBUG_JOBS, "%s pirority %d", EV_GET_TYPE_NAME (job), priority);
277 for (l = job_list; l; l = l->next) {
278 s_job = (EvSchedulerJob *)l->data;
280 if (s_job->job == job) {
281 need_resort = (s_job->priority != priority);
291 g_mutex_lock (job_queue_mutex);
293 list = g_queue_find (job_queue[s_job->priority], s_job);
295 ev_debug_message (DEBUG_JOBS, "Moving job %s from pirority %d to %d",
296 EV_GET_TYPE_NAME (job), s_job->priority, priority);
297 g_queue_delete_link (job_queue[s_job->priority], list);
298 g_queue_push_tail (job_queue[priority], s_job);
299 g_cond_broadcast (job_queue_cond);
302 g_mutex_unlock (job_queue_mutex);