Be more explicit about render jobs

Manage render jobs explicitly. This will help with situations where still have
an aborted request in the queue but a new render job has been requested.

Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
This commit is contained in:
Sebastian Ramacher 2013-11-07 12:36:21 +01:00
parent 11de9b606b
commit 63a4152f93

116
render.c
View file

@ -66,9 +66,9 @@ typedef struct private_s {
typedef struct request_private_s { typedef struct request_private_s {
ZathuraRenderer* renderer; ZathuraRenderer* renderer;
zathura_page_t* page; zathura_page_t* page;
volatile bool requested;
volatile bool aborted;
gint64 last_view_time; gint64 last_view_time;
girara_list_t* active_jobs;
mutex jobs_mutex;
} request_private_t; } request_private_t;
#define GET_PRIVATE(obj) \ #define GET_PRIVATE(obj) \
@ -77,6 +77,12 @@ typedef struct request_private_s {
(G_TYPE_INSTANCE_GET_PRIVATE((obj), ZATHURA_TYPE_RENDER_REQUEST, \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), ZATHURA_TYPE_RENDER_REQUEST, \
request_private_t)) request_private_t))
/* job descritption for render thread */
typedef struct render_job_s {
ZathuraRenderRequest* request;
volatile bool aborted;
} render_job_t;
/* init, new and free for ZathuraRenderer */ /* init, new and free for ZathuraRenderer */
static void static void
@ -247,8 +253,8 @@ zathura_render_request_new(ZathuraRenderer* renderer, zathura_page_t* page)
/* we want to make sure that renderer lives long enough */ /* we want to make sure that renderer lives long enough */
priv->renderer = g_object_ref(renderer); priv->renderer = g_object_ref(renderer);
priv->page = page; priv->page = page;
priv->aborted = false; priv->active_jobs = girara_list_new();
priv->requested = false; mutex_init(&priv->jobs_mutex);
/* register the request with the renderer */ /* register the request with the renderer */
renderer_register_request(renderer, request); renderer_register_request(renderer, request);
@ -268,6 +274,11 @@ render_request_finalize(GObject* object)
/* release our private reference to the renderer */ /* release our private reference to the renderer */
g_object_unref(priv->renderer); g_object_unref(priv->renderer);
} }
if (girara_list_size(priv->active_jobs) != 0) {
girara_error("This should not happen!");
}
girara_list_free(priv->active_jobs);
mutex_free(&priv->jobs_mutex);
} }
/* renderer methods */ /* renderer methods */
@ -396,14 +407,30 @@ zathura_render_request(ZathuraRenderRequest* request, gint64 last_view_time)
g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request)); g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));
request_private_t* request_priv = REQUEST_GET_PRIVATE(request); request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
if (request_priv->requested == false) { mutex_lock(&request_priv->jobs_mutex);
request_priv->requested = true;
request_priv->aborted = false; bool unfinished_jobs = false;
/* check if there are any active jobs left */
GIRARA_LIST_FOREACH(request_priv->active_jobs, render_job_t*, iter, job)
if (job->aborted != false) {
unfinished_jobs = true;
}
GIRARA_LIST_FOREACH_END(request_priv->active_jobs, render_job_t*, iter, job);
/* only add a new job if there are no active ones left */
if (unfinished_jobs == false) {
request_priv->last_view_time = last_view_time; request_priv->last_view_time = last_view_time;
render_job_t* job = g_malloc0(sizeof(render_job_t));
job->request = g_object_ref(request);
job->aborted = false;
girara_list_append(request_priv->active_jobs, job);
private_t* priv = GET_PRIVATE(request_priv->renderer); private_t* priv = GET_PRIVATE(request_priv->renderer);
g_thread_pool_push(priv->pool, request, NULL); g_thread_pool_push(priv->pool, job, NULL);
} }
mutex_unlock(&request_priv->jobs_mutex);
} }
void void
@ -412,9 +439,11 @@ zathura_render_request_abort(ZathuraRenderRequest* request)
g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request)); g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));
request_private_t* request_priv = REQUEST_GET_PRIVATE(request); request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
if (request_priv->requested == true) { mutex_lock(&request_priv->jobs_mutex);
request_priv->aborted = true; GIRARA_LIST_FOREACH(request_priv->active_jobs, render_job_t*, iter, job)
} job->aborted = true;
GIRARA_LIST_FOREACH_END(request_priv->active_jobs, render_job_t*, iter, job);
mutex_unlock(&request_priv->jobs_mutex);
} }
void void
@ -428,10 +457,22 @@ zathura_render_request_update_view_time(ZathuraRenderRequest* request)
/* render job */ /* render job */
static void
remove_job_and_free(render_job_t* job)
{
request_private_t* request_priv = REQUEST_GET_PRIVATE(job->request);
mutex_lock(&request_priv->jobs_mutex);
girara_list_remove(request_priv->active_jobs, job);
mutex_unlock(&request_priv->jobs_mutex);
g_object_unref(job->request);
g_free(job);
}
typedef struct emit_completed_signal_s typedef struct emit_completed_signal_s
{ {
ZathuraRenderer* renderer; render_job_t* job;
ZathuraRenderRequest* request;
cairo_surface_t* surface; cairo_surface_t* surface;
} emit_completed_signal_t; } emit_completed_signal_t;
@ -439,25 +480,24 @@ static gboolean
emit_completed_signal(void* data) emit_completed_signal(void* data)
{ {
emit_completed_signal_t* ecs = data; emit_completed_signal_t* ecs = data;
private_t* priv = GET_PRIVATE(ecs->renderer); render_job_t* job = ecs->job;
request_private_t* request_priv = REQUEST_GET_PRIVATE(ecs->request); request_private_t* request_priv = REQUEST_GET_PRIVATE(job->request);
private_t* priv = GET_PRIVATE(request_priv->renderer);
if (priv->about_to_close == false && request_priv->aborted == false) { if (priv->about_to_close == false && job->aborted == false) {
/* emit the signal */ /* emit the signal */
girara_debug("Emitting signal for page %d", girara_debug("Emitting signal for page %d",
zathura_page_get_index(request_priv->page) + 1); zathura_page_get_index(request_priv->page) + 1);
g_signal_emit(ecs->request, request_signals[REQUEST_COMPLETED], 0, ecs->surface); g_signal_emit(job->request, request_signals[REQUEST_COMPLETED], 0, ecs->surface);
} else { } else {
girara_debug("Rendering of page %d aborted", girara_debug("Rendering of page %d aborted",
zathura_page_get_index(request_priv->page) + 1); zathura_page_get_index(request_priv->page) + 1);
} }
/* mark the request as done */ /* mark the request as done */
request_priv->requested = false; remove_job_and_free(job);
/* clean up the data */ /* clean up the data */
cairo_surface_destroy(ecs->surface); cairo_surface_destroy(ecs->surface);
g_object_unref(ecs->renderer);
g_object_unref(ecs->request);
g_free(ecs); g_free(ecs);
return FALSE; return FALSE;
@ -598,7 +638,7 @@ recolor(private_t* priv, unsigned int page_width, unsigned int page_height,
} }
static bool static bool
render(ZathuraRenderRequest* request, ZathuraRenderer* renderer) render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* renderer)
{ {
private_t* priv = GET_PRIVATE(renderer); private_t* priv = GET_PRIVATE(renderer);
request_private_t* request_priv = REQUEST_GET_PRIVATE(request); request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
@ -650,10 +690,10 @@ render(ZathuraRenderRequest* request, ZathuraRenderer* renderer)
} }
/* before recoloring, check if we've been aborted */ /* before recoloring, check if we've been aborted */
if (priv->about_to_close == true || request_priv->aborted == true) { if (priv->about_to_close == true || job->aborted == true) {
girara_debug("Rendering of page %d aborted", girara_debug("Rendering of page %d aborted",
zathura_page_get_index(request_priv->page) + 1); zathura_page_get_index(request_priv->page) + 1);
request_priv->requested = false; remove_job_and_free(job);
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
return true; return true;
} }
@ -664,8 +704,7 @@ render(ZathuraRenderRequest* request, ZathuraRenderer* renderer)
} }
emit_completed_signal_t* ecs = g_malloc(sizeof(emit_completed_signal_t)); emit_completed_signal_t* ecs = g_malloc(sizeof(emit_completed_signal_t));
ecs->renderer = g_object_ref(renderer); ecs->job = job;
ecs->request = g_object_ref(request);
ecs->surface = cairo_surface_reference(surface); ecs->surface = cairo_surface_reference(surface);
/* emit signal from the main context, i.e. the main thread */ /* emit signal from the main context, i.e. the main thread */
@ -679,25 +718,26 @@ render(ZathuraRenderRequest* request, ZathuraRenderer* renderer)
static void static void
render_job(void* data, void* user_data) render_job(void* data, void* user_data)
{ {
ZathuraRenderRequest* request = data; render_job_t* job = data;
ZathuraRenderRequest* request = job->request;
ZathuraRenderer* renderer = user_data; ZathuraRenderer* renderer = user_data;
g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request)); g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));
g_return_if_fail(ZATHURA_IS_RENDERER(renderer)); g_return_if_fail(ZATHURA_IS_RENDERER(renderer));
private_t* priv = GET_PRIVATE(renderer); private_t* priv = GET_PRIVATE(renderer);
request_private_t* request_priv = REQUEST_GET_PRIVATE(request); if (priv->about_to_close == true || job->aborted == true) {
if (priv->about_to_close == true || request_priv->aborted == true) {
/* back out early */ /* back out early */
request_priv->requested = false; remove_job_and_free(job);
return; return;
} }
request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
girara_debug("Rendering page %d ...", girara_debug("Rendering page %d ...",
zathura_page_get_index(request_priv->page) + 1); zathura_page_get_index(request_priv->page) + 1);
if (render(request, renderer) != true) { if (render(job, request, renderer) != true) {
girara_error("Rendering failed (page %d)\n", girara_error("Rendering failed (page %d)\n",
zathura_page_get_index(request_priv->page) + 1); zathura_page_get_index(request_priv->page) + 1);
request_priv->requested = false; remove_job_and_free(job);
} }
} }
@ -732,20 +772,20 @@ render_thread_sort(gconstpointer a, gconstpointer b, gpointer UNUSED(data))
return 0; return 0;
} }
ZathuraRenderRequest* request_a = (ZathuraRenderRequest*) a; const render_job_t* job_a = a;
ZathuraRenderRequest* request_b = (ZathuraRenderRequest*) b; const render_job_t* job_b = b;
request_private_t* priv_a = REQUEST_GET_PRIVATE(request_a); if (job_a->aborted == job_b->aborted) {
request_private_t* priv_b = REQUEST_GET_PRIVATE(request_b); request_private_t* priv_a = REQUEST_GET_PRIVATE(job_a->request);
if (priv_a->aborted == priv_b->aborted) { request_private_t* priv_b = REQUEST_GET_PRIVATE(job_b->request);
return priv_a->last_view_time < priv_b->last_view_time ? -1 : return priv_a->last_view_time < priv_b->last_view_time ? -1 :
(priv_a->last_view_time > priv_b->last_view_time ? 1 : 0); (priv_a->last_view_time > priv_b->last_view_time ? 1 : 0);
} }
/* sort aborted entries earlier so that the are thrown out of the queue */ /* sort aborted entries earlier so that the are thrown out of the queue */
return priv_a->aborted ? 1 : -1; return job_a->aborted ? 1 : -1;
} }
/* cache functions */ /* cache functions */
static bool static bool