Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get into a joinable pthread state? #17984

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/common/darktable.c
Original file line number Diff line number Diff line change
Expand Up @@ -2060,12 +2060,6 @@ void dt_cleanup()
// we can no longer call dt_gui_process_events after this point, as that will cause a segfault
// if some delayed event fires

dt_image_cache_cleanup(darktable.image_cache);
free(darktable.image_cache);
darktable.image_cache = NULL;
dt_mipmap_cache_cleanup(darktable.mipmap_cache);
free(darktable.mipmap_cache);
darktable.mipmap_cache = NULL;
if(init_gui)
{
dt_imageio_cleanup(darktable.imageio);
Expand All @@ -2081,6 +2075,13 @@ void dt_cleanup()
darktable.gui = NULL;
}

dt_image_cache_cleanup(darktable.image_cache);
free(darktable.image_cache);
darktable.image_cache = NULL;
dt_mipmap_cache_cleanup(darktable.mipmap_cache);
free(darktable.mipmap_cache);
darktable.mipmap_cache = NULL;

dt_colorspaces_cleanup(darktable.color_profiles);
dt_conf_cleanup(darktable.conf);
free(darktable.conf);
Expand Down
89 changes: 44 additions & 45 deletions src/control/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ void dt_control_init(dt_control_t *s)
s->widget_definitions = g_ptr_array_new ();
s->input_drivers = NULL;
dt_atomic_set_int(&s->running, DT_CONTROL_STATE_DISABLED);
dt_atomic_set_int(&s->pending_jobs, 0);
dt_atomic_set_int(&s->quitting, 0);
s->cups_started = FALSE;

dt_action_define_fallback(DT_ACTION_TYPE_IOP, &dt_action_def_iop);
Expand Down Expand Up @@ -288,29 +290,32 @@ void dt_control_change_cursor(dt_cursor_t curs)

gboolean dt_control_running()
{
dt_control_t *dc = darktable.control;
const int status = dc ? dt_atomic_get_int(&dc->running) : DT_CONTROL_STATE_DISABLED;
return status == DT_CONTROL_STATE_RUNNING;
dt_control_t *control = darktable.control;
return control ? dt_atomic_get_int(&control->running) == DT_CONTROL_STATE_RUNNING : FALSE;
}

void dt_control_quit()
{
dt_control_t *control = darktable.control;
if(!control) return;

const gboolean quitting = dt_atomic_exch_int(&control->quitting, 1) == 1;
if(quitting) return;

if(dt_control_running())
{
dt_control_t *dc = darktable.control;

#ifdef HAVE_PRINT
dt_printers_abort_discovery();
// Cups timeout could be pretty long, at least 30seconds
// but don't rely on cups returning correctly so a timeout
for(int i = 0; i < 40000 && !dc->cups_started; i++)
for(int i = 0; i < 40000 && !control->cups_started; i++)
g_usleep(1000);
#endif

dt_pthread_mutex_lock(&dc->cond_mutex);
dt_pthread_mutex_lock(&control->cond_mutex);
// set the "pending cleanup work" flag to be handled in dt_control_shutdown()
dt_atomic_set_int(&dc->running, DT_CONTROL_STATE_CLEANUP);
dt_pthread_mutex_unlock(&dc->cond_mutex);
dt_atomic_set_int(&control->running, DT_CONTROL_STATE_CLEANUP);
dt_pthread_mutex_unlock(&control->cond_mutex);
}

if(g_atomic_int_get(&darktable.gui_running))
Expand All @@ -320,61 +325,55 @@ void dt_control_quit()
}
}

void dt_control_shutdown(dt_control_t *s)
void dt_control_shutdown(dt_control_t *control)
{
if(!s)
if(!control)
return;

dt_pthread_mutex_lock(&s->cond_mutex);
const gboolean cleanup = dt_atomic_exch_int(&s->running, DT_CONTROL_STATE_DISABLED) == DT_CONTROL_STATE_CLEANUP;
pthread_cond_broadcast(&s->cond);
dt_pthread_mutex_unlock(&s->cond_mutex);
dt_pthread_mutex_lock(&control->cond_mutex);
const gboolean cleanup = dt_atomic_exch_int(&control->running, DT_CONTROL_STATE_DISABLED) == DT_CONTROL_STATE_CLEANUP;
pthread_cond_broadcast(&control->cond);
dt_pthread_mutex_unlock(&control->cond_mutex);

int err = 0; // collect all joining errors
/* first wait for gphoto device updater */
#ifdef HAVE_GPHOTO2
err = pthread_join(s->update_gphoto_thread, NULL);
#endif
dt_print(DT_DEBUG_CONTROL, "[dt_control_shutdown] closing control threads%s, %d pending jobs",
cleanup ? " in cleanup mode" : "",
dt_control_jobs_pending(control));

if(!cleanup)
return; // if not running there are no threads to join

dt_print(DT_DEBUG_CONTROL, "[dt_control_shutdown] closing control threads");
#ifdef HAVE_GPHOTO2
/* first and always wait for gphoto device updater */
pthread_join(control->update_gphoto_thread, NULL);
#endif

/* then wait for kick_on_workers_thread */
err = pthread_join(s->kick_on_workers_thread, NULL);
dt_print(DT_DEBUG_CONTROL, "[dt_control_shutdown] joined kicker%s", err ? ", error" : "");
/* wait for kick_on_workers_thread */
pthread_join(control->kick_on_workers_thread, NULL);

for(int k = 0; k < s->num_threads-1; k++)
{
err = pthread_join(s->thread[k], NULL);
dt_print(DT_DEBUG_CONTROL, "[dt_control_shutdown] joined num_thread %i%s", k, err ? ", error" : "");
}
for(int k = 0; k < control->num_threads-1; k++)
pthread_join(control->thread[k], NULL);

for(int k = 0; k < DT_CTL_WORKER_RESERVED; k++)
{
err = pthread_join(s->thread_res[k], NULL);
dt_print(DT_DEBUG_CONTROL, "[dt_control_shutdown] joined worker %i%s", k, err ? ", error" : "");
}
pthread_join(control->thread_res[k], NULL);
}

void dt_control_cleanup(dt_control_t *s)
void dt_control_cleanup(dt_control_t *control)
{
if(!s)
if(!control)
return;
// vacuum TODO: optional?
// DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "PRAGMA incremental_vacuum(0)", NULL, NULL, NULL);
// DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "vacuum", NULL, NULL, NULL);
dt_control_jobs_cleanup(s);
dt_pthread_mutex_destroy(&s->queue_mutex);
dt_pthread_mutex_destroy(&s->cond_mutex);
dt_pthread_mutex_destroy(&s->log_mutex);
dt_pthread_mutex_destroy(&s->toast_mutex);
dt_pthread_mutex_destroy(&s->res_mutex);
dt_pthread_mutex_destroy(&s->progress_system.mutex);
if(s->widgets) g_hash_table_destroy(s->widgets);
if(s->shortcuts) g_sequence_free(s->shortcuts);
if(s->input_drivers) g_slist_free_full(s->input_drivers, g_free);
dt_control_jobs_cleanup(control);
dt_pthread_mutex_destroy(&control->queue_mutex);
dt_pthread_mutex_destroy(&control->cond_mutex);
dt_pthread_mutex_destroy(&control->log_mutex);
dt_pthread_mutex_destroy(&control->toast_mutex);
dt_pthread_mutex_destroy(&control->res_mutex);
dt_pthread_mutex_destroy(&control->progress_system.mutex);
if(control->widgets) g_hash_table_destroy(control->widgets);
if(control->shortcuts) g_sequence_free(control->shortcuts);
if(control->input_drivers) g_slist_free_full(control->input_drivers, g_free);
}


Expand Down
2 changes: 2 additions & 0 deletions src/control/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ typedef struct dt_control_t

// job management
dt_atomic_int running;
dt_atomic_int pending_jobs;
dt_atomic_int quitting;
gboolean cups_started;
gboolean export_scheduled;
dt_pthread_mutex_t queue_mutex, cond_mutex;
Expand Down
Loading
Loading