Files
OrcaSlicer/tests/libslic3r/CMakeLists.txt
T
Hanif Koh 5181a7fe26 Lock Config and Preset Files Across Instances and Write Them Atomically
Every running instance shares one OrcaSlicer.conf and one user preset
tree, and nothing kept their writers apart. Two instances saving at the
same moment, or the cloud preset sync thread writing while the GUI thread
saved, could interleave, and a reader in another instance could open a
preset JSON or .info file between truncate and close and get a partial
file, dropping that preset for the session with a parse error.

Add InstanceLock, a scoped guard that serialises the threads of one
process through a recursive mutex and other processes through an advisory
OS file lock, which the OS releases when its holder dies. It is best
effort: when the lock file cannot be created, or another instance still
holds it after two seconds, the guard logs a warning and lets the write
proceed rather than letting a hung instance block every other one.

AppConfig::save() and load() hold OrcaSlicer.conf.lock; load is included
because the Windows path restores from the .bak copy, and because Windows
cannot replace a file another process has open, so an unlocked reader
there made the other instance's save fail. Every user preset writer and
reader holds user.lock: Preset::save(), save_info(), load_info() and
remove_files(), the whole directory scan in load_presets(), the bundle
metadata file, the .info removal after a cloud-confirmed delete and the
bundle folder removal on unsubscribe. The guard sits at the leaf writers
on purpose: set_sync_info_and_save() calls save_info() under the preset
collection mutex, so a batch lock around save_user_presets(), which takes
that mutex through delete_preset(), would invert the order.

Write preset JSON, .info and bundle metadata files through a temporary
file beside the target that is renamed over it, so a reader that never
waits still sees a complete old or new file. On Linux and macOS
rename_file() deleted the target before renaming, leaving a window in
which the file did not exist at all, and returned a meaningless error
code on failure; rename() replaces atomically, so call it directly.
AppConfig::save() now logs a failed final rename instead of dropping the
save silently.
2026-09-24 02:36:05 +08:00

78 lines
2.1 KiB
CMake

get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
add_executable(${_TEST_NAME}_tests
${_TEST_NAME}_tests.cpp
test_3mf.cpp
test_aabbindirect.cpp
test_appconfig.cpp
test_arachne_walls.cpp
test_arrange.cpp
test_bambu_networking.cpp
test_buildvolume.cpp
test_calib.cpp
test_clipper_offset.cpp
test_clipper_utils.cpp
test_config.cpp
test_config_variant_expansion.cpp
test_toolordering_nozzle_group.cpp
test_preset_bundle_loading.cpp
test_preset_setting_id.cpp
test_preset_diff.cpp
test_vendor_cache.cpp
test_preset_options.cpp
test_elephant_foot_compensation.cpp
test_fill_corner_smoothing.cpp
test_filament_mixer.cpp
test_fill_plane_path.cpp
test_geometry.cpp
test_multimaterial_segmentation.cpp
test_placeholder_parser.cpp
test_polygon.cpp
test_mutable_polygon.cpp
test_mutable_priority_queue.cpp
test_minimum_spanning_tree.cpp
test_nozzle_volume_type.cpp
test_step.cpp
test_stl.cpp
test_triangle_selector.cpp
test_meshboolean.cpp
test_marchingsquares.cpp
test_lay_on_face.cpp
test_model.cpp
test_utils.cpp
test_timeutils.cpp
test_voronoi.cpp
test_wipe_tower_estimate.cpp
test_wipe_tower.cpp
test_wipe_path.cpp
test_optimizers.cpp
test_ordering_strategies.cpp
# test_png_io.cpp
test_indexed_triangle_set.cpp
test_instance_lock.cpp
../libnest2d/printer_parts.cpp
)
if (SLIC3R_CAD)
target_sources(${_TEST_NAME}_tests PRIVATE
test_caddocument.cpp
test_sketchconstraints.cpp
test_sketchedit.cpp
test_sketchprofile.cpp
test_sketchimport.cpp
test_sketchinference.cpp
test_slvs_constraints.cpp)
endif ()
if (TARGET OpenVDB::openvdb)
target_sources(${_TEST_NAME}_tests PRIVATE test_hollowing.cpp)
endif()
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r Catch2::Catch2WithMain)
target_include_directories(${_TEST_NAME}_tests PRIVATE ${CMAKE_SOURCE_DIR}/src)
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
orcaslicer_copy_test_dlls()
orcaslicer_discover_tests(${_TEST_NAME}_tests)