int32_t dt_control_add_job_res(dt_control_t *control, _dt_job_t *job, int32_t res) { if(((unsigned int)res) >= DT_CTL_WORKER_RESERVED || !job) { dt_control_job_dispose(job); return 1; } // TODO: pthread cancel and restart in tough cases? dt_pthread_mutex_lock(&control->queue_mutex); // if there is a job in the queue we have to discard that first if(control->job_res[res]) { dt_control_job_set_state(control->job_res[res], DT_JOB_STATE_DISCARDED); dt_control_job_dispose(control->job_res[res]); } dt_print(DT_DEBUG_CONTROL, "[add_job_res] %d | ", res); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); dt_control_job_set_state(job, DT_JOB_STATE_QUEUED); control->job_res[res] = job; control->new_res[res] = 1; dt_pthread_mutex_unlock(&control->queue_mutex); dt_pthread_mutex_lock(&control->cond_mutex); pthread_cond_broadcast(&control->cond); dt_pthread_mutex_unlock(&control->cond_mutex); return 0; }
dt_job_t *dt_camera_import_job_create(const char *jobcode, GList *images, struct dt_camera_t *camera, time_t time_override) { dt_job_t *job = dt_control_job_create(&dt_camera_import_job_run, "import selected images from camera"); if(!job) return NULL; dt_camera_import_t *params = dt_camera_import_alloc(); if(!params) { dt_control_job_dispose(job); return NULL; } dt_control_job_add_progress(job, _("import images from camera"), FALSE); dt_control_job_set_params(job, params, dt_camera_import_cleanup); /* intitialize import session for camera import job */ if(time_override != 0) dt_import_session_set_time(params->shared.session, time_override); dt_import_session_set_name(params->shared.session, jobcode); params->fraction = 0; params->images = g_list_copy(images); params->camera = camera; params->import_count = 0; params->job = job; return job; }
static int32_t dt_control_run_job(dt_control_t *control) { _dt_job_t *job = dt_control_schedule_job(control); if(!job) return -1; /* change state to running */ dt_pthread_mutex_lock(&job->wait_mutex); if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED) { dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); dt_control_job_set_state(job, DT_JOB_STATE_RUNNING); /* execute job */ job->result = job->execute(job); dt_control_job_set_state(job, DT_JOB_STATE_FINISHED); dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); } /* free job */ dt_pthread_mutex_unlock(&job->wait_mutex); dt_control_job_dispose(job); return 0; }
void dt_lua_init(lua_State*L,const char *lua_command) { /* Note to reviewers this is the only place where lua code is run without the lua lock. At this point, no user script has been called, so we are completely thread-safe. no need to lock This is also the only place where lua code is run with the gdk lock held, but this is not a problem because it is very brief, user calls are delegated to a secondary job */ char tmp_path[PATH_MAX]; // init the lua environment lua_CFunction* cur_type = init_funcs; while(*cur_type) { (*cur_type)(L); cur_type++; } // build the table containing the configuration info lua_getglobal(L,"package"); dt_lua_goto_subtable(L,"loaded"); lua_pushstring(L,"darktable"); dt_lua_push_darktable_lib(L); lua_settable(L,-3); lua_pop(L,1); lua_getglobal(L,"package"); lua_getfield(L,-1,"path"); lua_pushstring(L,";"); dt_loc_get_datadir(tmp_path, sizeof(tmp_path)); lua_pushstring(L,tmp_path); lua_pushstring(L,"/lua/?.lua"); lua_pushstring(L,";"); dt_loc_get_user_config_dir(tmp_path, sizeof(tmp_path)); lua_pushstring(L,tmp_path); lua_pushstring(L,"/lua/?.lua"); lua_concat(L,7); lua_setfield(L,-2,"path"); lua_pop(L,1); dt_job_t *job = dt_control_job_create(&run_early_script, "lua: run initial script"); dt_control_job_set_params(job, g_strdup(lua_command)); if(darktable.gui) { dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_BG, job); } else { run_early_script(job); dt_control_job_dispose(job); } }
static void free_params_wrapper(struct dt_imageio_module_storage_t *self, dt_imageio_module_data_t *data) { dt_job_t *job = dt_control_job_create(&free_param_wrapper_job, "lua: destroy storage param"); if(!job) return; free_param_wrapper_data *t = (free_param_wrapper_data *)calloc(1, sizeof(free_param_wrapper_data)); if(!t) { dt_control_job_dispose(job); return; } dt_control_job_set_params(job, t, free_param_wrapper_destroy); t->data = (lua_storage_t *)data; dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYSTEM_BG, job); }
dt_job_t * dt_image_load_job_create(int32_t id, dt_mipmap_size_t mip) { dt_job_t *job = dt_control_job_create(&dt_image_load_job_run, "load image %d mip %d", id, mip); if(!job) return NULL; dt_image_load_t *params = (dt_image_load_t *)calloc(1, sizeof(dt_image_load_t)); if(!params) { dt_control_job_dispose(job); return NULL; } dt_control_job_set_params(job, params); params->imgid = id; params->mip = mip; return job; }
dt_job_t * dt_image_import_job_create(uint32_t filmid, const char *filename) { dt_image_import_t *params; dt_job_t *job = dt_control_job_create(&dt_image_import_job_run, "import image"); if(!job) return NULL; params = (dt_image_import_t *)calloc(1, sizeof(dt_image_import_t)); if(!params) { dt_control_job_dispose(job); return NULL; } dt_control_job_set_params(job, params); params->filename = g_strdup(filename); params->film_id = filmid; return job; }
static void on_image_imported(gpointer instance,uint32_t id, gpointer user_data){ dt_job_t *job = dt_control_job_create(&on_image_imported_callback_job, "lua: on image imported"); if(job) { on_image_imported_callback_data_t *t = (on_image_imported_callback_data_t*)calloc(1, sizeof(on_image_imported_callback_data_t)); if(!t) { dt_control_job_dispose(job); } else { dt_control_job_set_params(job, t); t->imgid = id; dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, job); } } }
dt_job_t *dt_film_import1_create(dt_film_t *film) { dt_job_t *job = dt_control_job_create(&dt_film_import1_run, "cache load raw images for preview"); if(!job) return NULL; dt_film_import1_t *params = (dt_film_import1_t *)calloc(1, sizeof(dt_film_import1_t)); if(!params) { dt_control_job_dispose(job); return NULL; } dt_control_job_add_progress(job, _("import images"), FALSE); dt_control_job_set_params(job, params, dt_film_import1_cleanup); params->film = film; dt_pthread_mutex_lock(&film->images_mutex); film->ref++; dt_pthread_mutex_unlock(&film->images_mutex); return job; }
static void on_mouse_over_image_changed(gpointer instance, gpointer user_data) { dt_job_t *job = dt_control_job_create(&on_mouse_over_image_changed_callback_job, "lua: on mouse over image changed"); if(job) { on_mouse_over_image_changed_callback_data_t *t = (on_mouse_over_image_changed_callback_data_t *)calloc(1, sizeof(on_mouse_over_image_changed_callback_data_t)); if(!t) { dt_control_job_dispose(job); } else { dt_control_job_set_params(job, t); t->imgid = dt_control_get_mouse_over_id(); dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, job); } } }
dt_job_t *dt_camera_get_previews_job_create(dt_camera_t *camera, dt_camctl_listener_t *listener, uint32_t flags, void *data) { dt_job_t *job = dt_control_job_create(&dt_camera_get_previews_job_run, "get camera previews job"); if(!job) return NULL; dt_camera_get_previews_t *params = dt_camera_get_previews_alloc(); if(!params) { dt_control_job_dispose(job); return NULL; } dt_control_job_set_params(job, params, dt_camera_get_previews_cleanup); memcpy(params->listener, listener, sizeof(dt_camctl_listener_t)); params->camera = camera; params->flags = flags; params->data = data; return job; }
static void on_view_changed(gpointer instance, dt_view_t *old_view, dt_view_t *new_view, gpointer user_data) { dt_job_t *job = dt_control_job_create(&view_changed_callback_job, "lua: on view changed"); if(job) { view_changed_callback_data_t *t = (view_changed_callback_data_t *)calloc(1, sizeof(view_changed_callback_data_t)); if(!t) { dt_control_job_dispose(job); } else { dt_control_job_set_params(job, t); t->old_view = old_view; t->new_view = new_view; dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, job); } } }
static int32_t dt_control_run_job(dt_control_t *control) { _dt_job_t *job = dt_control_schedule_job(control); if(!job) return -1; /* change state to running */ dt_pthread_mutex_lock(&job->wait_mutex); if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED) { dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); dt_control_job_set_state(job, DT_JOB_STATE_RUNNING); /* execute job */ job->result = job->execute(job); dt_control_job_set_state(job, DT_JOB_STATE_FINISHED); dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); } dt_pthread_mutex_unlock(&job->wait_mutex); // remove the job from scheduled job array (for job deduping) dt_pthread_mutex_lock(&control->queue_mutex); control->job[dt_control_get_threadid()] = NULL; if(job->queue == DT_JOB_QUEUE_USER_EXPORT) control->export_scheduled = FALSE; dt_pthread_mutex_unlock(&control->queue_mutex); // and free it dt_control_job_dispose(job); return 0; }
dt_job_t * dt_camera_capture_job_create(const char *jobcode, uint32_t delay, uint32_t count, uint32_t brackets, uint32_t steps) { dt_job_t *job = dt_control_job_create(&dt_camera_capture_job_run, "remote capture of image(s)"); if(!job) return NULL; dt_camera_capture_t *params = (dt_camera_capture_t *)calloc(1, sizeof(dt_camera_capture_t)); if(!params) { dt_control_job_dispose(job); return NULL; } dt_control_job_set_params(job, params); params->shared.session = dt_import_session_new(); dt_import_session_set_name(params->shared.session, jobcode); params->delay=delay; params->count=count; params->brackets=brackets; params->steps=steps; return job; }
dt_job_t *dt_camera_capture_job_create(const char *jobcode, uint32_t delay, uint32_t count, uint32_t brackets, uint32_t steps) { dt_job_t *job = dt_control_job_create(&dt_camera_capture_job_run, "remote capture of image(s)"); if(!job) return NULL; dt_camera_capture_t *params = dt_camera_capture_alloc(); if(!params) { dt_control_job_dispose(job); return NULL; } dt_control_job_add_progress(job, _("capture images"), FALSE); dt_control_job_set_params(job, params, dt_camera_capture_cleanup); dt_import_session_set_name(params->shared.session, jobcode); params->delay = delay; params->count = count; params->brackets = brackets; params->steps = steps; return job; }
static int32_t dt_control_run_job_res(dt_control_t *control, int32_t res) { if(((unsigned int)res) >= DT_CTL_WORKER_RESERVED) return -1; _dt_job_t *job = NULL; dt_pthread_mutex_lock(&control->queue_mutex); if(control->new_res[res]) { job = control->job_res[res]; control->job_res[res] = NULL; // this job belongs to us now, the queue may not touch it any longer } control->new_res[res] = 0; dt_pthread_mutex_unlock(&control->queue_mutex); if(!job) return -1; /* change state to running */ dt_pthread_mutex_lock(&job->wait_mutex); if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED) { dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", res, dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); dt_control_job_set_state(job, DT_JOB_STATE_RUNNING); /* execute job */ job->result = job->execute(job); dt_control_job_set_state(job, DT_JOB_STATE_FINISHED); dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", res, dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); } dt_pthread_mutex_unlock(&job->wait_mutex); dt_control_job_dispose(job); return 0; }
static int32_t dt_control_run_job(dt_control_t *control) { _dt_job_t *job = dt_control_schedule_job(control); if(!job) return -1; /* change state to running */ dt_pthread_mutex_lock(&job->wait_mutex); if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED) dt_control_job_execute(job); dt_pthread_mutex_unlock(&job->wait_mutex); // remove the job from scheduled job array (for job deduping) dt_pthread_mutex_lock(&control->queue_mutex); control->job[dt_control_get_threadid()] = NULL; if(job->queue == DT_JOB_QUEUE_USER_EXPORT) control->export_scheduled = FALSE; dt_pthread_mutex_unlock(&control->queue_mutex); // and free it dt_control_job_dispose(job); return 0; }
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job) { if(((unsigned int)queue_id) >= DT_JOB_QUEUE_MAX || !job) { dt_control_job_dispose(job); return 1; } job->queue = queue_id; dt_pthread_mutex_lock(&control->queue_mutex); GList **queue = &control->queues[queue_id]; size_t length = control->queue_length[queue_id]; dt_print(DT_DEBUG_CONTROL, "[add_job] %ld | ", length); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); if(queue_id == DT_JOB_QUEUE_SYSTEM_FG) { // this is a stack with limited size and bubble up and all that stuff job->priority = DT_CONTROL_FG_PRIORITY; // if the job is already in the queue -> move it to the top for(GList *iter = *queue; iter; iter = g_list_next(iter)) { _dt_job_t *other_job = (_dt_job_t *)iter->data; if(dt_control_job_equal(job, other_job)) { dt_print(DT_DEBUG_CONTROL, "[add_job] found job already in queue: "); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); *queue = g_list_delete_link(*queue, iter); length--; dt_control_job_set_state(job, DT_JOB_STATE_DISCARDED); dt_control_job_dispose(job); job = other_job; break; // there can't be any further copy in the list } } // now we can add the new job to the list *queue = g_list_prepend(*queue, job); length++; // and take care of the maximal queue size if(length > DT_CONTROL_MAX_JOBS) { GList *last = g_list_last(*queue); dt_control_job_set_state((_dt_job_t *)last->data, DT_JOB_STATE_DISCARDED); *queue = g_list_delete_link(*queue, last); length--; } control->queue_length[queue_id] = length; } else { // the rest are FIFOs if(queue_id == DT_JOB_QUEUE_USER_BG || queue_id == DT_JOB_QUEUE_SYSTEM_BG) job->priority = 0; else job->priority = DT_CONTROL_FG_PRIORITY; *queue = g_list_append(*queue, job); control->queue_length[queue_id]++; } dt_control_job_set_state(job, DT_JOB_STATE_QUEUED); dt_pthread_mutex_unlock(&control->queue_mutex); // notify workers dt_pthread_mutex_lock(&control->cond_mutex); pthread_cond_broadcast(&control->cond); dt_pthread_mutex_unlock(&control->cond_mutex); return 0; }
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job) { if(((unsigned int)queue_id) >= DT_JOB_QUEUE_MAX || !job) { dt_control_job_dispose(job); return 1; } if(!control->running) { // whatever we are adding here won't be scheduled as the system isn't running. execute it synchronous instead. dt_pthread_mutex_lock(&job->wait_mutex); // is that even needed? dt_control_job_execute(job); dt_pthread_mutex_unlock(&job->wait_mutex); dt_control_job_dispose(job); return 0; } job->queue = queue_id; _dt_job_t *job_for_disposal = NULL; dt_pthread_mutex_lock(&control->queue_mutex); GList **queue = &control->queues[queue_id]; size_t length = control->queue_length[queue_id]; dt_print(DT_DEBUG_CONTROL, "[add_job] %zu | ", length); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); if(queue_id == DT_JOB_QUEUE_SYSTEM_FG) { // this is a stack with limited size and bubble up and all that stuff job->priority = DT_CONTROL_FG_PRIORITY; // check if we have already scheduled the job for(int k = 0; k < control->num_threads; k++) { _dt_job_t *other_job = (_dt_job_t *)control->job[k]; if(dt_control_job_equal(job, other_job)) { dt_print(DT_DEBUG_CONTROL, "[add_job] found job already in scheduled: "); dt_control_job_print(other_job); dt_print(DT_DEBUG_CONTROL, "\n"); dt_pthread_mutex_unlock(&control->queue_mutex); dt_control_job_set_state(job, DT_JOB_STATE_DISCARDED); dt_control_job_dispose(job); return 0; // there can't be any further copy } } // if the job is already in the queue -> move it to the top for(GList *iter = *queue; iter; iter = g_list_next(iter)) { _dt_job_t *other_job = (_dt_job_t *)iter->data; if(dt_control_job_equal(job, other_job)) { dt_print(DT_DEBUG_CONTROL, "[add_job] found job already in queue: "); dt_control_job_print(other_job); dt_print(DT_DEBUG_CONTROL, "\n"); *queue = g_list_delete_link(*queue, iter); length--; job_for_disposal = job; job = other_job; break; // there can't be any further copy in the list } } // now we can add the new job to the list *queue = g_list_prepend(*queue, job); length++; // and take care of the maximal queue size if(length > DT_CONTROL_MAX_JOBS) { GList *last = g_list_last(*queue); dt_control_job_set_state((_dt_job_t *)last->data, DT_JOB_STATE_DISCARDED); dt_control_job_dispose((_dt_job_t *)last->data); *queue = g_list_delete_link(*queue, last); length--; } control->queue_length[queue_id] = length; } else { // the rest are FIFOs if(queue_id == DT_JOB_QUEUE_USER_BG || queue_id == DT_JOB_QUEUE_USER_EXPORT || queue_id == DT_JOB_QUEUE_SYSTEM_BG) job->priority = 0; else job->priority = DT_CONTROL_FG_PRIORITY; *queue = g_list_append(*queue, job); control->queue_length[queue_id]++; } dt_control_job_set_state(job, DT_JOB_STATE_QUEUED); dt_pthread_mutex_unlock(&control->queue_mutex); // notify workers dt_pthread_mutex_lock(&control->cond_mutex); pthread_cond_broadcast(&control->cond); dt_pthread_mutex_unlock(&control->cond_mutex); // dispose of dropped job, if any dt_control_job_set_state(job_for_disposal, DT_JOB_STATE_DISCARDED); dt_control_job_dispose(job_for_disposal); return 0; }