From e71d27db284ccf431167816167bf72f1e23c334d Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Sun, 03 Aug 2008 11:01:28 +0000 Subject: Rework the jobs system in order to make it simpler and more extensible. It 2008-08-03 Carlos Garcia Campos * libdocument/ev-document.[ch]: (ev_document_doc_mutex_trylock), (ev_document_fc_mutex_trylock): * shell/Makefile.am: * shell/ev-job-queue.[ch]: * shell/ev-job-scheduler.[ch]: * shell/ev-jobs.[ch]: (ev_job_init), (ev_job_dispose), (ev_job_class_init), (emit_finished), (ev_job_emit_finished), (ev_job_run), (ev_job_cancel), (ev_job_failed), (ev_job_failed_from_error), (ev_job_succeeded), (ev_job_is_finished), (ev_job_is_failed), (ev_job_get_run_mode), (ev_job_set_run_mode), (ev_job_links_init), (ev_job_links_run), (ev_job_links_class_init), (ev_job_render_init), (notify_page_ready), (ev_job_render_page_ready), (ev_job_render_run), (ev_job_render_class_init), (ev_job_thumbnail_init), (ev_job_thumbnail_run), (ev_job_thumbnail_class_init), (ev_job_fonts_init), (ev_job_fonts_run), (ev_job_fonts_class_init), (ev_job_load_init), (ev_job_load_run), (ev_job_load_class_init), (ev_job_save_init), (ev_job_save_dispose), (ev_job_save_run), (ev_job_save_class_init), (ev_job_print_init), (ev_job_print_dispose), (ev_job_print_run), (ev_job_print_class_init): * shell/ev-page-cache.c: * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info), (check_job_size_and_unref), (move_one_job), (copy_job_to_job_info), (add_job), (ev_pixbuf_cache_add_jobs_if_needed): * shell/ev-properties-fonts.c: (ev_properties_fonts_dispose), (job_fonts_finished_cb), (job_fonts_updated_cb), (ev_properties_fonts_set_document): * shell/ev-sidebar-links.c: (ev_sidebar_links_dispose), (ev_sidebar_links_set_document): * shell/ev-sidebar-thumbnails.c: (clear_range), (add_range), (ev_sidebar_thumbnails_set_document), (ev_sidebar_thumbnails_clear_job): * shell/ev-view-private.h: * shell/ev-view.c: * shell/ev-window.c: (ev_window_clear_thumbnail_job), (ev_window_refresh_window_thumbnail), (password_dialog_response), (ev_window_clear_load_job), (ev_window_clear_reload_job), (ev_window_load_job_cb), (ev_window_reload_job_cb), (window_open_file_copy_ready_cb), (ev_window_open_uri), (ev_window_reload_document), (ev_window_clear_save_job), (ev_window_save_job_cb), (file_save_dialog_response_cb), (ev_window_clear_print_job), (ev_window_print_job_cb), (ev_window_print_dialog_response_cb): * shell/main.c: (main): Rework the jobs system in order to make it simpler and more extensible. It allows to run jobs in the main loop instead of using a thread when it's appropriate like the fonts job. Now it's also possible to cancel jobs that are currently running. svn path=/trunk/; revision=3092 --- (limited to 'shell/ev-job-queue.c') diff --git a/shell/ev-job-queue.c b/shell/ev-job-queue.c deleted file mode 100644 index 8280aab..0000000 --- a/shell/ev-job-queue.c +++ /dev/null @@ -1,517 +0,0 @@ -#include -#include "ev-job-queue.h" - -/* Like glib calling convention, all functions with _locked in their name assume - * that we've already locked the doc mutex and can freely and safely access - * data. - */ -GCond *render_cond = NULL; -GMutex *ev_queue_mutex = NULL; - -static GQueue *links_queue = NULL; -static GQueue *render_queue_high = NULL; -static GQueue *render_queue_low = NULL; -static GQueue *thumbnail_queue_high = NULL; -static GQueue *thumbnail_queue_low = NULL; -static GQueue *load_queue = NULL; -static GQueue *save_queue = NULL; -static GQueue *fonts_queue = NULL; -static GQueue *print_queue = NULL; - -/* Queues used for backends supporting EvAsyncRender interface, - they are executed on the main thread */ -static GQueue *async_render_queue_high = NULL; -static GQueue *async_render_queue_low = NULL; -static gboolean async_rendering = FALSE; - -static void ev_job_queue_run_next (void); - -static gboolean -remove_job_from_queue_locked (GQueue *queue, EvJob *job) -{ - GList *list; - - list = g_queue_find (queue, job); - if (list) { - g_object_unref (G_OBJECT (job)); - g_queue_delete_link (queue, list); - - return TRUE; - } - return FALSE; -} - -static gboolean -remove_job_from_async_queue (GQueue *queue, EvJob *job) -{ - return remove_job_from_queue_locked (queue, job); -} - -static void -add_job_to_async_queue (GQueue *queue, EvJob *job) -{ - g_object_ref (job); - g_queue_push_tail (queue, job); -} - -/** - * add_job_to_queue_locked: - * @queue: a #GQueue where the #EvJob will be added. - * @job: an #EvJob to be added to the specified #GQueue. - * - * Add the #EvJob to the specified #GQueue and woke up the ev_render_thread who - * is waiting for render_cond. - */ -static void -add_job_to_queue_locked (GQueue *queue, - EvJob *job) -{ - g_object_ref (job); - g_queue_push_tail (queue, job); - g_cond_broadcast (render_cond); -} - -/** - * notify_finished: - * @job: the object that signal will be reseted. - * - * It does emit the job finished signal and returns %FALSE. - * - * Returns: %FALSE. - */ -static gboolean -notify_finished (GObject *job) -{ - ev_job_finished (EV_JOB (job)); - - return FALSE; -} - -/** - * job_finished_cb: - * @job: the #EvJob that has been handled. - * - * It does finish the job last work and look if there is any more job to be - * handled. - */ -static void -job_finished_cb (EvJob *job) -{ - g_object_unref (job); - async_rendering = FALSE; - ev_job_queue_run_next (); -} - -/** - * handle_job: - * @job: the #EvJob to be handled. - * - * First, it does check if the job is async and then it does attend it if - * possible giving a failed assertion otherwise. If the job isn't async it does - * attend it and notify that the job has been finished. - */ -static void -handle_job (EvJob *job) -{ - g_object_ref (G_OBJECT (job)); - - if (EV_JOB (job)->async) { - async_rendering = TRUE; - if (EV_IS_JOB_RENDER (job)) { - g_signal_connect (job, "finished", - G_CALLBACK (job_finished_cb), NULL); - } else { - g_assert_not_reached (); - } - } - - if (EV_IS_JOB_THUMBNAIL (job)) - ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job)); - else if (EV_IS_JOB_LINKS (job)) - ev_job_links_run (EV_JOB_LINKS (job)); - else if (EV_IS_JOB_LOAD (job)) - ev_job_load_run (EV_JOB_LOAD (job)); - else if (EV_IS_JOB_SAVE (job)) - ev_job_save_run (EV_JOB_SAVE (job)); - else if (EV_IS_JOB_RENDER (job)) - ev_job_render_run (EV_JOB_RENDER (job)); - else if (EV_IS_JOB_FONTS (job)) - ev_job_fonts_run (EV_JOB_FONTS (job)); - else if (EV_IS_JOB_PRINT (job)) - ev_job_print_run (EV_JOB_PRINT (job)); - - if (!EV_JOB (job)->async) { - /* We let the idle own a ref, as we (the queue) are done with the job. */ - g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, - (GSourceFunc) notify_finished, - job, - g_object_unref); - } -} - -/** - * search_for_jobs_unlocked: - * - * Check if there is any job at the synchronized queues and return any existing - * job in them taking in account the next priority: - * - * render_queue_high > - * thumbnail_queue_high > - * render_queue_low > - * links_queue > - * load_queue > - * thumbnail_queue_low > - * fonts_queue > - * print_queue > - * - * Returns: an available #EvJob in the queues taking in account stablished queue - * priorities. - */ -static EvJob * -search_for_jobs_unlocked (void) -{ - EvJob *job; - - job = (EvJob *) g_queue_pop_head (render_queue_high); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (thumbnail_queue_high); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (render_queue_low); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (links_queue); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (load_queue); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (save_queue); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (thumbnail_queue_low); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (fonts_queue); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (print_queue); - if (job) - return job; - - return NULL; -} - -/** - * no_jobs_available_unlocked: - * - * Looks if there is any job at render, links, load, thumbnail. fonts and print - * queues. - * - * Returns: %TRUE if the render, links, load, thumbnail, fonts and print queues - * are empty, %FALSE in other case. - */ -static gboolean -no_jobs_available_unlocked (void) -{ - return g_queue_is_empty (render_queue_high) - && g_queue_is_empty (render_queue_low) - && g_queue_is_empty (links_queue) - && g_queue_is_empty (load_queue) - && g_queue_is_empty (save_queue) - && g_queue_is_empty (thumbnail_queue_high) - && g_queue_is_empty (thumbnail_queue_low) - && g_queue_is_empty (fonts_queue) - && g_queue_is_empty (print_queue); -} - -/* the thread mainloop function */ -/** - * ev_render_thread: - * @data: data passed to the thread. - * - * The thread mainloop function. It does wait for any available job in synced - * queues to handle it. - * - * Returns: the return value of the thread, which will be returned by - * g_thread_join(). - */ -static gpointer -ev_render_thread (gpointer data) -{ - while (TRUE) { - EvJob *job; - - g_mutex_lock (ev_queue_mutex); - if (no_jobs_available_unlocked ()) { - g_cond_wait (render_cond, ev_queue_mutex); - } - - job = search_for_jobs_unlocked (); - g_mutex_unlock (ev_queue_mutex); - - /* Now that we have our job, we handle it */ - if (job) { - handle_job (job); - g_object_unref (G_OBJECT (job)); - } - } - return NULL; - -} - -/** - * ev_job_queue_run_next: - * - * It does look for any job on the render high priority queue first and after - * in the render low priority one, and then it does handle it. - */ -static void -ev_job_queue_run_next (void) -{ - EvJob *job; - - job = (EvJob *) g_queue_pop_head (async_render_queue_high); - - if (job == NULL) { - job = (EvJob *) g_queue_pop_head (async_render_queue_low); - } - - /* Now that we have our job, we handle it */ - if (job) { - handle_job (job); - g_object_unref (G_OBJECT (job)); - } -} - -/* Public Functions */ -/** - * ev_job_queue_init: - * - * Creates a new cond, new mutex, a thread for evince job handling and inits - * every queue. - */ -void -ev_job_queue_init (void) -{ - if (!g_thread_supported ()) g_thread_init (NULL); - - render_cond = g_cond_new (); - ev_queue_mutex = g_mutex_new (); - - links_queue = g_queue_new (); - load_queue = g_queue_new (); - save_queue = g_queue_new (); - render_queue_high = g_queue_new (); - render_queue_low = g_queue_new (); - async_render_queue_high = g_queue_new (); - async_render_queue_low = g_queue_new (); - thumbnail_queue_high = g_queue_new (); - thumbnail_queue_low = g_queue_new (); - fonts_queue = g_queue_new (); - print_queue = g_queue_new (); - - g_thread_create (ev_render_thread, NULL, FALSE, NULL); - -} - -static GQueue * -find_queue (EvJob *job, - EvJobPriority priority) -{ - if (EV_JOB (job)->async) { - if (EV_IS_JOB_RENDER (job)) { - if (priority == EV_JOB_PRIORITY_HIGH) - return async_render_queue_high; - else - return async_render_queue_low; - } - } else { - if (EV_IS_JOB_RENDER (job)) { - if (priority == EV_JOB_PRIORITY_HIGH) - return render_queue_high; - else - return render_queue_low; - } else if (EV_IS_JOB_THUMBNAIL (job)) { - if (priority == EV_JOB_PRIORITY_HIGH) - return thumbnail_queue_high; - else - return thumbnail_queue_low; - } else if (EV_IS_JOB_LOAD (job)) { - /* the priority doesn't effect load */ - return load_queue; - } else if (EV_IS_JOB_SAVE (job)) { - /* the priority doesn't effect save */ - return save_queue; - } else if (EV_IS_JOB_LINKS (job)) { - /* the priority doesn't effect links */ - return links_queue; - } else if (EV_IS_JOB_FONTS (job)) { - /* the priority doesn't effect fonts */ - return fonts_queue; - } else if (EV_IS_JOB_PRINT (job)) { - /* the priority doesn't effect print */ - return print_queue; - } - } - - g_assert_not_reached (); - return NULL; -} - -void -ev_job_queue_add_job (EvJob *job, - EvJobPriority priority) -{ - GQueue *queue; - - g_return_if_fail (EV_IS_JOB (job)); - - queue = find_queue (job, priority); - - if (!EV_JOB (job)->async) { - g_mutex_lock (ev_queue_mutex); - add_job_to_queue_locked (queue, job); - g_mutex_unlock (ev_queue_mutex); - } else { - add_job_to_async_queue (queue, job); - if (!async_rendering) { - ev_job_queue_run_next (); - } - } -} - -static gboolean -move_job_async (EvJob *job, GQueue *old_queue, GQueue *new_queue) -{ - gboolean retval = FALSE; - - g_object_ref (job); - - if (remove_job_from_queue_locked (old_queue, job)) { - add_job_to_async_queue (new_queue, job); - retval = TRUE; - } - - g_object_unref (job); - - return retval; -} - -static gboolean -move_job (EvJob *job, GQueue *old_queue, GQueue *new_queue) -{ - gboolean retval = FALSE; - - g_mutex_lock (ev_queue_mutex); - g_object_ref (job); - - if (remove_job_from_queue_locked (old_queue, job)) { - add_job_to_queue_locked (new_queue, job); - retval = TRUE; - } - - g_object_unref (job); - g_mutex_unlock (ev_queue_mutex); - - return retval; -} - -gboolean -ev_job_queue_update_job (EvJob *job, - EvJobPriority new_priority) -{ - gboolean retval = FALSE; - - g_return_val_if_fail (EV_IS_JOB (job), FALSE); - - if (EV_JOB (job)->async) { - if (EV_IS_JOB_RENDER (job)) { - if (new_priority == EV_JOB_PRIORITY_LOW) { - retval = move_job_async (job, async_render_queue_high, - async_render_queue_low); - } else if (new_priority == EV_JOB_PRIORITY_HIGH) { - retval = move_job_async (job, async_render_queue_low, - async_render_queue_high); - } - } else { - g_assert_not_reached (); - } - } else { - if (EV_IS_JOB_THUMBNAIL (job)) { - if (new_priority == EV_JOB_PRIORITY_LOW) { - retval = move_job (job, thumbnail_queue_high, - thumbnail_queue_low); - } else if (new_priority == EV_JOB_PRIORITY_HIGH) { - retval = move_job (job, thumbnail_queue_low, - thumbnail_queue_high); - } - } else if (EV_IS_JOB_RENDER (job)) { - if (new_priority == EV_JOB_PRIORITY_LOW) { - retval = move_job (job, render_queue_high, - render_queue_low); - } else if (new_priority == EV_JOB_PRIORITY_HIGH) { - retval = move_job (job, render_queue_low, - render_queue_high); - } - } else { - g_assert_not_reached (); - } - } - - return retval; -} - -gboolean -ev_job_queue_remove_job (EvJob *job) -{ - gboolean retval = FALSE; - - g_return_val_if_fail (EV_IS_JOB (job), FALSE); - - if (EV_JOB (job)->async) { - if (EV_IS_JOB_RENDER (job)) { - retval = remove_job_from_async_queue (async_render_queue_high, job); - retval = retval || remove_job_from_async_queue (async_render_queue_low, job); - } else { - g_assert_not_reached (); - } - } else { - g_mutex_lock (ev_queue_mutex); - - if (EV_IS_JOB_THUMBNAIL (job)) { - retval = remove_job_from_queue_locked (thumbnail_queue_high, job); - retval = retval || remove_job_from_queue_locked (thumbnail_queue_low, job); - } else if (EV_IS_JOB_RENDER (job)) { - retval = remove_job_from_queue_locked (render_queue_high, job); - retval = retval || remove_job_from_queue_locked (render_queue_low, job); - } else if (EV_IS_JOB_LINKS (job)) { - retval = remove_job_from_queue_locked (links_queue, job); - } else if (EV_IS_JOB_LOAD (job)) { - retval = remove_job_from_queue_locked (load_queue, job); - } else if (EV_IS_JOB_SAVE (job)) { - retval = remove_job_from_queue_locked (save_queue, job); - } else if (EV_IS_JOB_FONTS (job)) { - retval = remove_job_from_queue_locked (fonts_queue, job); - } else if (EV_IS_JOB_PRINT (job)) { - retval = remove_job_from_queue_locked (print_queue, job); - } else { - g_assert_not_reached (); - } - - g_mutex_unlock (ev_queue_mutex); - } - - return retval; -} - - -- cgit v0.9.1