Fix ':close' command

Currently, zathura crashes while performing ':close' command with the
following error:

GThread-ERROR **: file gthread-posix.c: line 226
(g_cond_free_posix_impl): error 'Device or resource busy' during
'pthread_cond_destroy ((pthread_cond_t *) cond)'

The error is because 'render' thread holds condition variable while
waiting for new pages to render. This patch modifies zathura's code to
correctly kill render thread and free allocated resources when the
document is being closed.

NOTE: should be applied on top of "Allow changing of "pages-per-row"
variable at runtime" commit to avoid conflicts in the
'page_view_set_mode()' function.

Signed-off-by: Pavel Borzenkov <pavel.borzenkov@gmail.com>
This commit is contained in:
Pavel Borzenkov 2011-07-21 16:39:25 +04:00 committed by Sebastian Ramacher
parent 333cfa4df0
commit caccb94c69
3 changed files with 34 additions and 11 deletions

View file

@ -305,6 +305,7 @@ zathura_document_free(zathura_document_t* document)
for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++)
{
zathura_page_free(document->pages[page_id]);
document->pages[page_id] = NULL;
}
free(document->pages);
@ -427,6 +428,8 @@ zathura_page_free(zathura_page_t* page)
return false;
}
g_static_mutex_free(&(page->lock));
return page->document->functions.page_free(page);
}

View file

@ -17,6 +17,17 @@ render_job(void* data)
g_cond_wait(render_thread->cond, render_thread->lock);
}
if (girara_list_size(render_thread->list) <= 0) {
/*
* We've been signaled with g_cond_signal(), but the list
* is still empty. This means that the signal came from
* render_free() and current document is being closed.
* We should unlock the mutex and kill the thread.
*/
g_mutex_unlock(render_thread->lock);
g_thread_exit(0);
}
zathura_page_t* page = (zathura_page_t*) girara_list_nth(render_thread->list, 0);
girara_list_remove(render_thread->list, page);
g_mutex_unlock(render_thread->lock);
@ -104,6 +115,8 @@ render_free(render_thread_t* render_thread)
}
if (render_thread->cond) {
g_cond_signal(render_thread->cond);
g_thread_join(render_thread->thread);
g_cond_free(render_thread->cond);
}

View file

@ -308,6 +308,16 @@ error_out:
return false;
}
static void
remove_page_from_table(GtkWidget* page, gpointer permanent)
{
if (!permanent) {
g_object_ref(G_OBJECT(page));
}
gtk_container_remove(GTK_CONTAINER(page->parent), page);
}
bool
document_close(zathura_t* zathura)
{
@ -315,11 +325,15 @@ document_close(zathura_t* zathura)
return false;
}
if (zathura->sync.render_thread) {
render_free(zathura->sync.render_thread);
}
render_free(zathura->sync.render_thread);
zathura->sync.render_thread = NULL;
gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_view), remove_page_from_table, (gpointer)1);
zathura_document_free(zathura->document);
zathura->document = NULL;
gtk_widget_hide_all(zathura->ui.page_view);
return true;
}
@ -378,8 +392,6 @@ statusbar_page_number_update(zathura_t* zathura)
void
page_view_set_mode(zathura_t* zathura, unsigned int pages_per_row)
{
GList* child;
/* show at least one page */
if (pages_per_row == 0) {
pages_per_row = 1;
@ -389,12 +401,7 @@ page_view_set_mode(zathura_t* zathura, unsigned int pages_per_row)
return;
}
child = gtk_container_get_children(GTK_CONTAINER(zathura->ui.page_view));
while (child) {
g_object_ref(G_OBJECT(child->data));
gtk_container_remove(GTK_CONTAINER(zathura->ui.page_view), GTK_WIDGET(child->data));
child = g_list_next(child);
}
gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_view), remove_page_from_table, (gpointer)0);
gtk_table_resize(GTK_TABLE(zathura->ui.page_view), zathura->document->number_of_pages / pages_per_row + 1, pages_per_row);
for (unsigned int i = 0; i < zathura->document->number_of_pages; i++)