]> www.fi.muni.cz Git - evince.git/blob - backend/ev-job-queue.c
merge evince-threads branch
[evince.git] / backend / ev-job-queue.c
1 #include "ev-job-queue.h"
2
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
5  * data.
6  */
7 GCond *render_cond = NULL;
8 GMutex *ev_queue_mutex = NULL;
9
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
16 static gboolean
17 remove_object_from_queue (GQueue *queue, EvJob *job)
18 {
19         GList *list;
20
21         list = g_queue_find (queue, job);
22         if (list) {
23                 g_object_unref (G_OBJECT (job));
24                 g_queue_delete_link (queue, list);
25
26                 return TRUE;
27         }
28         return FALSE;
29 }
30
31
32 static gboolean
33 notify_finished (GObject *job)
34 {
35         ev_job_finished (EV_JOB (job));
36
37         return FALSE;
38 }
39
40
41 static void
42 handle_job (EvJob *job)
43 {
44         g_object_ref (G_OBJECT (job));
45
46         if (EV_IS_JOB_THUMBNAIL (job))
47                 ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job));
48         else if (EV_IS_JOB_LINKS (job))
49                 ev_job_links_run (EV_JOB_LINKS (job));
50         else if (EV_IS_JOB_RENDER (job))
51                 ev_job_render_run (EV_JOB_RENDER (job));
52
53         /* We let the idle own a ref, as we (the queue) are done with the job. */
54         g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
55                          (GSourceFunc) notify_finished,
56                          job,
57                          g_object_unref);
58 }
59
60 static EvJob *
61 search_for_jobs_unlocked (void)
62 {
63         EvJob *job;
64
65         job = (EvJob *) g_queue_pop_head (render_queue_high);
66         if (job)
67                 return job;
68
69         job = (EvJob *) g_queue_pop_head (thumbnail_queue_high);
70         if (job)
71                 return job;
72
73         job = (EvJob *) g_queue_pop_head (render_queue_low);
74         if (job)
75                 return job;
76
77         job = (EvJob *) g_queue_pop_head (links_queue);
78         if (job)
79                 return job;
80
81         job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
82         if (job)
83                 return job;
84
85         return NULL;
86 }
87
88 static gboolean
89 no_jobs_available_unlocked (void)
90 {
91         return g_queue_is_empty (render_queue_high)
92                 && g_queue_is_empty (render_queue_low)
93                 && g_queue_is_empty (links_queue)
94                 && g_queue_is_empty (thumbnail_queue_high)
95                 && g_queue_is_empty (thumbnail_queue_low);
96 }
97
98 /* the thread mainloop function */
99 static gpointer
100 ev_render_thread (gpointer data)
101 {
102         while (TRUE) {
103                 EvJob *job;
104
105                 g_mutex_lock (ev_queue_mutex);
106                 if (no_jobs_available_unlocked ()) {
107                         g_cond_wait (render_cond, ev_queue_mutex);
108                 }
109
110                 job = search_for_jobs_unlocked ();
111                 g_mutex_unlock (ev_queue_mutex);
112
113                 /* Now that we have our job, we handle it */
114                 if (job) {
115                         handle_job (job);
116                         g_object_unref (G_OBJECT (job));
117                 }
118         }
119         return NULL;
120
121 }
122
123 /* Public Functions */
124 void
125 ev_job_queue_init (void)
126 {
127         if (!g_thread_supported ()) g_thread_init (NULL);
128
129         render_cond = g_cond_new ();
130         ev_queue_mutex = g_mutex_new ();
131
132         links_queue = g_queue_new ();
133         render_queue_high = g_queue_new ();
134         render_queue_low = g_queue_new ();
135         thumbnail_queue_high = g_queue_new ();
136         thumbnail_queue_low = g_queue_new ();
137
138         g_thread_create (ev_render_thread, NULL, FALSE, NULL);
139
140 }
141
142 static GQueue *
143 find_queue (EvJob         *job,
144             EvJobPriority  priority)
145 {
146         if (EV_IS_JOB_RENDER (job)) {
147                 if (priority == EV_JOB_PRIORITY_HIGH)
148                         return render_queue_high;
149                 else
150                         return render_queue_low;
151         } else if (EV_IS_JOB_THUMBNAIL (job)) {
152                 if (priority == EV_JOB_PRIORITY_HIGH)
153                         return thumbnail_queue_high;
154                 else
155                         return thumbnail_queue_low;
156         } else if (EV_IS_JOB_LINKS (job)) {
157                 /* the priority doesn't effect links */
158                 return links_queue;
159         }
160
161         g_assert_not_reached ();
162         return NULL;
163 }
164
165 void
166 ev_job_queue_add_job (EvJob         *job,
167                       EvJobPriority  priority)
168 {
169         GQueue *queue;
170
171         g_return_if_fail (EV_IS_JOB (job));
172
173         queue = find_queue (job, priority);
174
175         g_mutex_lock (ev_queue_mutex);
176
177         g_object_ref (job);
178         g_queue_push_tail (queue, job);
179         g_cond_broadcast (render_cond);
180
181         g_mutex_unlock (ev_queue_mutex);
182         
183 }
184
185 gboolean
186 ev_job_queue_remove_job (EvJob *job)
187 {
188         gboolean retval = FALSE;
189
190         g_return_val_if_fail (EV_IS_JOB (job), FALSE);
191
192         g_mutex_lock (ev_queue_mutex);
193
194         if (EV_IS_JOB_THUMBNAIL (job)) {
195                 retval = remove_object_from_queue (thumbnail_queue_high, job);
196                 retval = retval || remove_object_from_queue (thumbnail_queue_low, job);
197         } else if (EV_IS_JOB_RENDER (job)) {
198                 retval = remove_object_from_queue (render_queue_high, job);
199                 retval = retval || remove_object_from_queue (render_queue_low, job);
200         } else if (EV_IS_JOB_LINKS (job)) {
201                 retval = remove_object_from_queue (links_queue, job);
202         } else {
203                 g_assert_not_reached ();
204         }
205         
206         g_mutex_unlock (ev_queue_mutex);
207
208         return retval;
209 }
210
211