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 {
ZathuraRenderer* renderer;
zathura_page_t* page;
volatile bool requested;
volatile bool aborted;
gint64 last_view_time;
girara_list_t* active_jobs;
mutex jobs_mutex;
} request_private_t;
#define GET_PRIVATE(obj) \
@ -77,6 +77,12 @@ typedef struct request_private_s {
(G_TYPE_INSTANCE_GET_PRIVATE((obj), ZATHURA_TYPE_RENDER_REQUEST, \
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 */
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 */
priv->renderer = g_object_ref(renderer);
priv->page = page;
priv->aborted = false;
priv->requested = false;
priv->active_jobs = girara_list_new();
mutex_init(&priv->jobs_mutex);
/* register the request with the renderer */
renderer_register_request(renderer, request);
@ -268,6 +274,11 @@ render_request_finalize(GObject* object)
/* release our private reference to the 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 */
@ -396,14 +407,30 @@ zathura_render_request(ZathuraRenderRequest* request, gint64 last_view_time)
g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));
request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
if (request_priv->requested == false) {
request_priv->requested = true;
request_priv->aborted = false;
mutex_lock(&request_priv->jobs_mutex);
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;
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);
g_thread_pool_push(priv->pool, request, NULL);
g_thread_pool_push(priv->pool, job, NULL);
}
mutex_unlock(&request_priv->jobs_mutex);
}
void
@ -412,9 +439,11 @@ zathura_render_request_abort(ZathuraRenderRequest* request)
g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));
request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
if (request_priv->requested == true) {
request_priv->aborted = true;
}
mutex_lock(&request_priv->jobs_mutex);
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
@ -428,10 +457,22 @@ zathura_render_request_update_view_time(ZathuraRenderRequest* request)
/* 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
{
ZathuraRenderer* renderer;
ZathuraRenderRequest* request;
render_job_t* job;
cairo_surface_t* surface;
} emit_completed_signal_t;
@ -439,25 +480,24 @@ static gboolean
emit_completed_signal(void* data)
{
emit_completed_signal_t* ecs = data;
private_t* priv = GET_PRIVATE(ecs->renderer);
request_private_t* request_priv = REQUEST_GET_PRIVATE(ecs->request);
render_job_t* job = ecs->job;
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 */
girara_debug("Emitting signal for page %d",
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 {
girara_debug("Rendering of page %d aborted",
zathura_page_get_index(request_priv->page) + 1);
}
/* mark the request as done */
request_priv->requested = false;
remove_job_and_free(job);
/* clean up the data */
cairo_surface_destroy(ecs->surface);
g_object_unref(ecs->renderer);
g_object_unref(ecs->request);
g_free(ecs);
return FALSE;
@ -598,7 +638,7 @@ recolor(private_t* priv, unsigned int page_width, unsigned int page_height,
}
static bool
render(ZathuraRenderRequest* request, ZathuraRenderer* renderer)
render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* renderer)
{
private_t* priv = GET_PRIVATE(renderer);
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 */
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",
zathura_page_get_index(request_priv->page) + 1);
request_priv->requested = false;
remove_job_and_free(job);
cairo_surface_destroy(surface);
return true;
}
@ -664,8 +704,7 @@ render(ZathuraRenderRequest* request, ZathuraRenderer* renderer)
}
emit_completed_signal_t* ecs = g_malloc(sizeof(emit_completed_signal_t));
ecs->renderer = g_object_ref(renderer);
ecs->request = g_object_ref(request);
ecs->job = job;
ecs->surface = cairo_surface_reference(surface);
/* emit signal from the main context, i.e. the main thread */
@ -679,25 +718,26 @@ render(ZathuraRenderRequest* request, ZathuraRenderer* renderer)
static void
render_job(void* data, void* user_data)
{
ZathuraRenderRequest* request = data;
render_job_t* job = data;
ZathuraRenderRequest* request = job->request;
ZathuraRenderer* renderer = user_data;
g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));
g_return_if_fail(ZATHURA_IS_RENDERER(renderer));
private_t* priv = GET_PRIVATE(renderer);
request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
if (priv->about_to_close == true || request_priv->aborted == true) {
if (priv->about_to_close == true || job->aborted == true) {
/* back out early */
request_priv->requested = false;
remove_job_and_free(job);
return;
}
request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
girara_debug("Rendering page %d ...",
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",
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;
}
ZathuraRenderRequest* request_a = (ZathuraRenderRequest*) a;
ZathuraRenderRequest* request_b = (ZathuraRenderRequest*) b;
request_private_t* priv_a = REQUEST_GET_PRIVATE(request_a);
request_private_t* priv_b = REQUEST_GET_PRIVATE(request_b);
if (priv_a->aborted == priv_b->aborted) {
const render_job_t* job_a = a;
const render_job_t* job_b = b;
if (job_a->aborted == job_b->aborted) {
request_private_t* priv_a = REQUEST_GET_PRIVATE(job_a->request);
request_private_t* priv_b = REQUEST_GET_PRIVATE(job_b->request);
return priv_a->last_view_time < priv_b->last_view_time ? -1 :
(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 */
return priv_a->aborted ? 1 : -1;
return job_a->aborted ? 1 : -1;
}
/* cache functions */
static bool