// moved out of control.c to be able to make some helper functions static void dt_control_jobs_init(dt_control_t *control) { // start threads control->num_threads = CLAMP(dt_conf_get_int("worker_threads"), 1, 8); control->thread = (pthread_t *)calloc(control->num_threads, sizeof(pthread_t)); control->job = (dt_job_t **)calloc(control->num_threads, sizeof(dt_job_t *)); dt_pthread_mutex_lock(&control->run_mutex); control->running = 1; dt_pthread_mutex_unlock(&control->run_mutex); for(int k = 0; k < control->num_threads; k++) { worker_thread_parameters_t *params = (worker_thread_parameters_t *)calloc(1, sizeof(worker_thread_parameters_t)); params->self = control; params->threadid = k; pthread_create(&control->thread[k], NULL, dt_control_work, params); } /* create queue kicker thread */ pthread_create(&control->kick_on_workers_thread, NULL, dt_control_worker_kicker, control); for(int k = 0; k < DT_CTL_WORKER_RESERVED; k++) { control->job_res[k] = NULL; control->new_res[k] = 0; worker_thread_parameters_t *params = (worker_thread_parameters_t *)calloc(1, sizeof(worker_thread_parameters_t)); params->self = control; params->threadid = k; pthread_create(&control->thread_res[k], NULL, dt_control_work_res, params); } }
void gui_update(dt_iop_module_t *self) { dt_iop_levels_gui_data_t *g = (dt_iop_levels_gui_data_t *)self->gui_data; dt_iop_levels_params_t *p = (dt_iop_levels_params_t *)self->params; dt_bauhaus_combobox_set(g->mode, g_list_index(g->modes, GUINT_TO_POINTER(p->mode))); dt_bauhaus_slider_set(g->percentile_black, p->percentiles[0]); dt_bauhaus_slider_set(g->percentile_grey, p->percentiles[1]); dt_bauhaus_slider_set(g->percentile_white, p->percentiles[2]); switch(p->mode) { case LEVELS_MODE_AUTOMATIC: gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "automatic"); break; case LEVELS_MODE_MANUAL: default: gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual"); break; } dt_pthread_mutex_lock(&g->lock); g->auto_levels[0] = NAN; g->auto_levels[1] = NAN; g->auto_levels[2] = NAN; g->hash = 0; dt_pthread_mutex_unlock(&g->lock); gtk_widget_queue_draw(self->widget); }
dt_dev_zoom_t dt_control_get_dev_zoom() { dt_pthread_mutex_lock(&(darktable.control->global_mutex)); dt_dev_zoom_t result = darktable.control->dev_zoom; dt_pthread_mutex_unlock(&(darktable.control->global_mutex)); return result; }
static void *dt_control_work_res(void *ptr) { #ifdef _OPENMP // need to do this in every thread omp_set_num_threads(darktable.num_openmp_threads); #endif worker_thread_parameters_t *params = (worker_thread_parameters_t *)ptr; dt_control_t *s = params->self; threadid = params->threadid; free(params); int32_t threadid_res = dt_control_get_threadid_res(); while(dt_control_running()) { // dt_print(DT_DEBUG_CONTROL, "[control_work] %d\n", threadid_res); if(dt_control_run_job_res(s, threadid_res) < 0) { // wait for a new job. int old; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old); dt_pthread_mutex_lock(&s->cond_mutex); dt_pthread_cond_wait(&s->cond, &s->cond_mutex); dt_pthread_mutex_unlock(&s->cond_mutex); int tmp; pthread_setcancelstate(old, &tmp); } } return NULL; }
int dt_control_get_dev_closeup() { dt_pthread_mutex_lock(&(darktable.control->global_mutex)); int result = darktable.control->dev_closeup; dt_pthread_mutex_unlock(&(darktable.control->global_mutex)); return result; }
int32_t dt_control_get_mouse_over_id() { dt_pthread_mutex_lock(&(darktable.control->global_mutex)); int32_t result = darktable.control->mouse_over_id; dt_pthread_mutex_unlock(&(darktable.control->global_mutex)); return result; }
static void dt_control_log_ack_all() { dt_pthread_mutex_lock(&darktable.control->log_mutex); darktable.control->log_pos = darktable.control->log_ack; dt_pthread_mutex_unlock(&darktable.control->log_mutex); dt_control_queue_redraw_center(); }
static int lua_job_progress(lua_State *L) { dt_progress_t *progress; luaA_to(L, dt_lua_backgroundjob_t, &progress, 1); dt_pthread_mutex_lock(&darktable.control->progress_system.mutex); GList *iter = g_list_find(darktable.control->progress_system.list, progress); dt_pthread_mutex_unlock(&darktable.control->progress_system.mutex); if(!iter) luaL_error(L, "Accessing an invalid job"); if(lua_isnone(L, 3)) { double result = dt_control_progress_get_progress(progress); if(!dt_control_progress_has_progress_bar(progress)) lua_pushnil(L); else lua_pushnumber(L, result); return 1; } else { double value; luaA_to(L, progress_double, &value, 3); dt_control_progress_set_progress(darktable.control, progress, value); return 0; } }
static int lua_job_valid(lua_State *L) { dt_progress_t *progress; luaA_to(L, dt_lua_backgroundjob_t, &progress, 1); if(lua_isnone(L, 3)) { dt_pthread_mutex_lock(&darktable.control->progress_system.mutex); GList *iter = g_list_find(darktable.control->progress_system.list, progress); dt_pthread_mutex_unlock(&darktable.control->progress_system.mutex); if(iter) lua_pushboolean(L, true); else lua_pushboolean(L, false); return 1; } else { int validity = lua_toboolean(L, 3); if(validity) return luaL_argerror(L, 3, "a job can not be made valid"); dt_control_progress_destroy(darktable.control, progress); return 0; } }
void dt_lua_unlock_internal(const char *function, int line) { #ifdef _DEBUG dt_print(DT_DEBUG_LUA,"LUA DEBUG : %s called from %s %d\n",__FUNCTION__,function,line); #endif dt_pthread_mutex_unlock(&darktable.lua_state.mutex); }
void dt_opencl_unlock_device(const int dev) { dt_opencl_t *cl = darktable.opencl; if(!cl->inited) return; if(dev < 0 || dev >= cl->num_devs) return; dt_pthread_mutex_unlock(&cl->dev[dev].lock); }
/** gui callbacks, these are needed. */ void gui_update(dt_iop_module_t *self) { // let gui slider match current parameters: dt_iop_bilat_gui_data_t *g = (dt_iop_bilat_gui_data_t *)self->gui_data; dt_iop_bilat_params_t *p = (dt_iop_bilat_params_t *)self->params; dt_bauhaus_slider_set(g->detail, 100.0f*p->detail+100.0f); dt_bauhaus_combobox_set(g->mode, p->mode); if(p->mode == s_mode_local_laplacian) { dt_bauhaus_slider_set(g->shadows, p->sigma_s*100.0f); dt_bauhaus_slider_set(g->highlights, p->sigma_r*100.0f); dt_bauhaus_slider_set(g->midtone, p->midtone); gtk_widget_set_visible(g->range, FALSE); gtk_widget_set_visible(g->spatial, FALSE); gtk_widget_set_visible(g->highlights, TRUE); gtk_widget_set_visible(g->shadows, TRUE); gtk_widget_set_visible(g->midtone, TRUE); dt_pthread_mutex_lock(&g->lock); g->hash = 0; dt_pthread_mutex_unlock(&g->lock); } else { dt_bauhaus_slider_set(g->spatial, p->sigma_s); dt_bauhaus_slider_set(g->range, p->sigma_r); gtk_widget_set_visible(g->range, TRUE); gtk_widget_set_visible(g->spatial, TRUE); gtk_widget_set_visible(g->highlights, FALSE); gtk_widget_set_visible(g->shadows, FALSE); gtk_widget_set_visible(g->midtone, FALSE); } }
dt_job_state_t dt_control_job_get_state(_dt_job_t *job) { if(!job) return DT_JOB_STATE_DISPOSED; dt_pthread_mutex_lock(&job->state_mutex); dt_job_state_t state = job->state; dt_pthread_mutex_unlock(&job->state_mutex); return state; }
void dt_capabilities_remove(char *capability) { dt_pthread_mutex_lock(&darktable.capabilities_threadsafe); darktable.capabilities = g_list_remove(darktable.capabilities, capability); dt_pthread_mutex_unlock(&darktable.capabilities_threadsafe); }
void dt_control_log_busy_leave() { dt_pthread_mutex_lock(&darktable.control->log_mutex); darktable.control->log_busy--; dt_pthread_mutex_unlock(&darktable.control->log_mutex); /* lets redraw */ dt_control_queue_redraw_center(); }
void dt_lua_unlock(gboolean relock_gdk) { dt_pthread_mutex_unlock(&darktable.lua_state.mutex); if(relock_gdk) { dt_control_gdk_lock(); } }
// return read locked bucket, or NULL if it's not already there. // never attempt to allocate a new slot. dt_cache_entry_t *dt_cache_testget(dt_cache_t *cache, const uint32_t key, char mode) { gpointer orig_key, value; gboolean res; int result; double start = dt_get_wtime(); dt_pthread_mutex_lock(&cache->lock); res = g_hash_table_lookup_extended( cache->hashtable, GINT_TO_POINTER(key), &orig_key, &value); if(res) { dt_cache_entry_t *entry = (dt_cache_entry_t *)value; // lock the cache entry if(mode == 'w') result = dt_pthread_rwlock_trywrlock(&entry->lock); else result = dt_pthread_rwlock_tryrdlock(&entry->lock); if(result) { // need to give up mutex so other threads have a chance to get in between and // free the lock we're trying to acquire: dt_pthread_mutex_unlock(&cache->lock); return 0; } // bubble up in lru list: cache->lru = g_list_remove_link(cache->lru, entry->link); cache->lru = g_list_concat(cache->lru, entry->link); dt_pthread_mutex_unlock(&cache->lock); double end = dt_get_wtime(); if(end - start > 0.1) fprintf(stderr, "try+ wait time %.06fs mode %c \n", end - start, mode); if(mode == 'w') { assert(entry->data_size); ASAN_POISON_MEMORY_REGION(entry->data, entry->data_size); } // WARNING: do *NOT* unpoison here. it must be done by the caller! return entry; } dt_pthread_mutex_unlock(&cache->lock); double end = dt_get_wtime(); if(end - start > 0.1) fprintf(stderr, "try- wait time %.06fs\n", end - start); return 0; }
void dt_capabilities_add(char *capability) { dt_pthread_mutex_lock(&darktable.capabilities_threadsafe); if(!dt_capabilities_check(capability)) darktable.capabilities = g_list_append(darktable.capabilities, capability); dt_pthread_mutex_unlock(&darktable.capabilities_threadsafe); }
void dt_camctl_unregister_listener( const dt_camctl_t *c, dt_camctl_listener_t *listener) { dt_camctl_t *camctl=(dt_camctl_t *)c; // Just locking mutex and prevent signalling CAMERA_CONTROL_BUSY dt_pthread_mutex_lock(&camctl->lock); dt_print(DT_DEBUG_CAMCTL,"[camera_control] unregistering listener %lx\n",(unsigned long int)listener); camctl->listeners = g_list_remove( camctl->listeners, listener ); dt_pthread_mutex_unlock(&camctl->lock); }
void dt_control_progress_set_progress(dt_control_t *control, dt_progress_t *progress, double value) { // set the value dt_pthread_mutex_lock(&progress->mutex); progress->progress = value; dt_pthread_mutex_unlock(&progress->mutex); // tell the gui dt_pthread_mutex_lock(&control->progress_system.mutex); if(control->progress_system.proxy.module != NULL) control->progress_system.proxy.updated(control->progress_system.proxy.module, progress->gui_data, value); dt_pthread_mutex_unlock(&control->progress_system.mutex); #ifdef HAVE_UNITY if(progress->has_progress_bar) unity_launcher_entry_set_progress(progress->darktable_launcher, CLAMP(value, 0, 1.0)); #endif }
void dt_control_quit() { #ifdef HAVE_MAP // since map mode doesn't like to quit we just switch to lighttable mode. hacky, but it works :( if(dt_conf_get_int("ui_last/view") == DT_MAP) // we are in map mode where no expose is running dt_ctl_switch_mode_to(DT_LIBRARY); #endif dt_gui_gtk_quit(); // thread safe quit, 1st pass: dt_pthread_mutex_lock(&darktable.control->cond_mutex); dt_pthread_mutex_lock(&darktable.control->run_mutex); darktable.control->running = 0; dt_pthread_mutex_unlock(&darktable.control->run_mutex); dt_pthread_mutex_unlock(&darktable.control->cond_mutex); // let gui pick up the running = 0 state and die gtk_widget_queue_draw(dt_ui_center(darktable.gui->ui)); }
void _camctl_unlock(const dt_camctl_t *c) { dt_camctl_t *camctl=(dt_camctl_t *)c; const dt_camera_t *cam=camctl->active_camera; camctl->active_camera=NULL; dt_pthread_mutex_unlock(&camctl->lock); dt_print(DT_DEBUG_CAMCTL,"[camera_control] camera control un-locked for camera %lx\n",(unsigned long int)cam); _dispatch_control_status(c,CAMERA_CONTROL_AVAILABLE); }
int dt_control_running() { // FIXME: when shutdown, run_mutex is not inited anymore! dt_control_t *s = darktable.control; dt_pthread_mutex_lock(&s->run_mutex); int running = s->running; dt_pthread_mutex_unlock(&s->run_mutex); return running; }
static void dt_control_job_set_state(_dt_job_t *job, dt_job_state_t state) { if(!job) return; dt_pthread_mutex_lock(&job->state_mutex); job->state = state; /* pass state change to callback */ if(job->state_changed_cb) job->state_changed_cb(job, state); dt_pthread_mutex_unlock(&job->state_mutex); }
void dt_control_init(dt_control_t *s) { memset(s->vimkey, 0, sizeof(s->vimkey)); s->vimkey_cnt = 0; // same thread as init s->gui_thread = pthread_self(); // initialize static mutex dt_pthread_mutex_init(&_control_gdk_lock_threads_mutex, NULL); // s->last_expose_time = dt_get_wtime(); s->key_accelerators_on = 1; s->log_pos = s->log_ack = 0; s->log_busy = 0; s->log_message_timeout_id = 0; dt_pthread_mutex_init(&(s->log_mutex), NULL); s->progress = 200.0f; dt_conf_set_int("ui_last/view", DT_MODE_NONE); pthread_cond_init(&s->cond, NULL); dt_pthread_mutex_init(&s->cond_mutex, NULL); dt_pthread_mutex_init(&s->queue_mutex, NULL); dt_pthread_mutex_init(&s->run_mutex, NULL); pthread_rwlock_init(&s->xprofile_lock, NULL); dt_pthread_mutex_init(&(s->global_mutex), NULL); dt_pthread_mutex_init(&(s->image_mutex), NULL); // start threads s->num_threads = CLAMP(dt_conf_get_int ("worker_threads"), 1, 8); s->thread = (pthread_t *)malloc(sizeof(pthread_t)*s->num_threads); dt_pthread_mutex_lock(&s->run_mutex); s->running = 1; dt_pthread_mutex_unlock(&s->run_mutex); for(int k=0; k<s->num_threads; k++) pthread_create(&s->thread[k], NULL, dt_control_work, s); /* create queue kicker thread */ pthread_create(&s->kick_on_workers_thread, NULL, _control_worker_kicker, s); for(int k=0; k<DT_CTL_WORKER_RESERVED; k++) { s->new_res[k] = 0; pthread_create(&s->thread_res[k], NULL, dt_control_work_res, s); dt_pthread_mutex_init(&s->job_res[k].state_mutex, NULL); dt_pthread_mutex_init(&s->job_res[k].wait_mutex, NULL); } s->button_down = 0; s->button_down_which = 0; s->mouse_over_id = -1; s->dev_closeup = 0; s->dev_zoom_x = 0; s->dev_zoom_y = 0; s->dev_zoom = DT_ZOOM_FIT; }
void dt_film_import1_init(dt_job_t *job, dt_film_t *film) { dt_control_job_init(job, "cache load raw images for preview"); job->execute = &dt_film_import1_run; dt_film_import1_t *t = (dt_film_import1_t *)job->param; t->film = film; dt_pthread_mutex_lock(&film->images_mutex); film->ref++; dt_pthread_mutex_unlock(&film->images_mutex); }
static gboolean _dt_ctl_log_message_timeout_callback(gpointer data) { dt_pthread_mutex_lock(&darktable.control->log_mutex); if(darktable.control->log_ack != darktable.control->log_pos) darktable.control->log_ack = (darktable.control->log_ack + 1) % DT_CTL_LOG_SIZE; darktable.control->log_message_timeout_id = 0; dt_pthread_mutex_unlock(&darktable.control->log_mutex); dt_control_queue_redraw_center(); return FALSE; }
void _control_job_set_state(dt_job_t *j,int state) { dt_pthread_mutex_lock (&j->state_mutex); j->state = state; /* pass state change to callback */ if (j->state_changed_cb) j->state_changed_cb (j,state); dt_pthread_mutex_unlock (&j->state_mutex); }
void dt_dev_module_remove(dt_develop_t *dev, dt_iop_module_t *module) { //if(darktable.gui->reset) return; dt_pthread_mutex_lock(&dev->history_mutex); int del = 0; if(dev->gui_attached) { int nb = g_list_length(dev->history); int pos = 0; for (int i=0; i<nb; i++) { GList *elem = g_list_nth(dev->history,pos); dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(elem->data); if (module->instance == hist->module->instance && module->multi_priority == hist->module->multi_priority) { free(hist->params); free(hist->blend_params); free(hist); dev->history = g_list_delete_link(dev->history, elem); dev->history_end--; del = 1; } else { pos++; } } } dt_pthread_mutex_unlock(&dev->history_mutex); //and we remove it from the list GList *modules = g_list_first(dev->iop); while(modules) { dt_iop_module_t *mod = (dt_iop_module_t *)modules->data; if(mod == module) { dev->iop = g_list_remove_link(dev->iop,modules); break; } modules = g_list_next(modules); } if(dev->gui_attached && del) { /* signal that history has changed */ dt_control_signal_raise(darktable.signals, DT_SIGNAL_DEVELOP_HISTORY_CHANGE); /* redraw */ dt_control_queue_redraw_center(); } }
void gui_update(struct dt_iop_module_t *self) { dt_iop_exposure_gui_data_t *g = (dt_iop_exposure_gui_data_t *)self->gui_data; dt_iop_exposure_params_t *p = (dt_iop_exposure_params_t *)self->params; if(!dt_image_is_raw(&self->dev->image_storage)) { gtk_widget_hide(GTK_WIDGET(g->mode)); p->mode = EXPOSURE_MODE_MANUAL; dt_dev_add_history_item(darktable.develop, self, TRUE); } else { gtk_widget_show(GTK_WIDGET(g->mode)); } dt_bauhaus_combobox_set(g->mode, g_list_index(g->modes, GUINT_TO_POINTER(p->mode))); dt_bauhaus_slider_set_soft(g->black, p->black); dt_bauhaus_slider_set_soft(g->exposure, p->exposure); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->autoexp), FALSE); dt_bauhaus_slider_set(g->autoexpp, 0.01); gtk_widget_set_sensitive(GTK_WIDGET(g->autoexpp), FALSE); dt_bauhaus_slider_set(g->deflicker_percentile, p->deflicker_percentile); dt_bauhaus_slider_set(g->deflicker_target_level, p->deflicker_target_level); dt_bauhaus_combobox_set( g->deflicker_histogram_source, g_list_index(g->deflicker_histogram_sources, GUINT_TO_POINTER(p->deflicker_histogram_source))); self->request_color_pick = DT_REQUEST_COLORPICK_OFF; free(g->deflicker_histogram); g->deflicker_histogram = NULL; gtk_label_set_text(g->deflicker_used_EC, ""); dt_pthread_mutex_lock(&g->lock); g->deflicker_computed_exposure = NAN; dt_pthread_mutex_unlock(&g->lock); switch(p->mode) { case EXPOSURE_MODE_DEFLICKER: autoexp_disable(self); gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "deflicker"); if(p->deflicker_histogram_source == DEFLICKER_HISTOGRAM_SOURCE_SOURCEFILE) deflicker_prepare_histogram(self, &g->deflicker_histogram, &g->deflicker_histogram_stats); break; case EXPOSURE_MODE_MANUAL: default: gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual"); break; } }