Skip to content

Commit 3cc3ee3

Browse files
committed
Fix startup race condition
Fixrare race condition between OpenCL background job and `dt_wb_presets_init`. In darktable.c:1878-1887, the GUI startup path queues OpenCL detection as a background job on the system worker pool and then immediately continues to call `dt_wb_presets_init(NULL)`. `dt_opencl_init` (called by a worker thread) loads OpenCL vendor libraries (ICD loader, driver). These vendor libraries are known to call `setlocale()` internally. `setlocale()` in glibc: * Acquires `__libc_setlocale_lock` * Frees and replaces internal locale data structures (including cached locale strings) Meanwhile, the main thread is inside `dcigettext` → `guess_category_value` → `getenv("LANGUAGE")`. The glibc `dcigettext` code is not re-entrant with `setlocale()`: it caches locale state that can be freed mid-read when `setlocale()` runs concurrently, leading to a SIGSEGV. This does not happen in the non-GUI/CLI path (`init_gui=0`) because there `dt_opencl_init` is called synchronously before `dt_wb_presets_init`. Potential fixes: * Move `dt_wb_presets_init` (and `dt_noiseprofile_init`) to before the OpenCL background job is enqueued, so the JSON/gettext code finishes before any worker thread starts running the OCL job. In darktable.c around line 1876. The fix is confirmed clean for the non-GUI path since it already calls `dt_opencl_init` synchronously — the proposed reorder makes both paths consistent. * Alternatively, a more targeted fix is to call `setlocale(LC_ALL, "")` once and freeze it (or save/restore it around `dt_opencl_init`) before JSON parsing begins, but reordering the init sequence is cleaner and less invasive.
1 parent 791cf93 commit 3cc3ee3

1 file changed

Lines changed: 12 additions & 10 deletions

File tree

src/common/darktable.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,23 +1873,25 @@ int dt_init(int argc,
18731873
heif_init(NULL);
18741874
#endif
18751875

1876+
dt_splash_screen_set_progress(_("initializing WB presets"));
1877+
dt_wb_presets_init(NULL);
1878+
1879+
// Do locale-sensitive init BEFORE starting any background worker jobs
1880+
dt_splash_screen_set_progress(_("loading noise profiles"));
1881+
darktable.noiseprofile_parser = dt_noiseprofile_init(noiseprofiles_from_command);
1882+
18761883
dt_splash_screen_set_progress(_("starting OpenCL"));
18771884
darktable.opencl = (dt_opencl_t *)calloc(1, sizeof(dt_opencl_t));
1885+
darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t));
1886+
dt_points_init(darktable.points, dt_get_num_threads());
1887+
1888+
// Only then kick off the OpenCL background job
18781889
if(init_gui)
18791890
dt_control_add_job(DT_JOB_QUEUE_SYSTEM_BG, _detect_opencl_job_create(exclude_opencl));
18801891
else
18811892
dt_opencl_init(darktable.opencl, exclude_opencl, print_statistics);
18821893

1883-
darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t));
1884-
dt_points_init(darktable.points, dt_get_num_threads());
1885-
1886-
dt_wb_presets_init(NULL);
1887-
1888-
dt_splash_screen_set_progress(_("loading noise profiles"));
1889-
darktable.noiseprofile_parser = dt_noiseprofile_init(noiseprofiles_from_command);
1890-
1891-
// must come before mipmap_cache, because that one will need to access
1892-
// image dimensions stored in here:
1894+
// must come before mipmap_cache, because that one will need to access image dimensions stored in here:
18931895
dt_image_cache_init();
18941896

18951897
dt_mipmap_cache_init();

0 commit comments

Comments
 (0)