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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, 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);