Fix ScheduleManager start() self-deadlock on cached schedule
start() held mutex_ and then called loadCache(), which re-locks the same non-recursive mutex. When a schedule cache file exists and parses (the normal case for a provisioned kiosk), this self-deadlocks and blocks SDL_AppInit before the first frame, leaving only a black screen and the compositor cursor. Narrow the lock to the member setup so loadCache() can take the lock itself. Add a regression test that starts with a cached payload present.
This commit is contained in:
@@ -87,16 +87,20 @@ void ScheduleManager::refreshOnce() {
|
||||
|
||||
void ScheduleManager::start(db::DatabaseManager& db, const std::string& timezone,
|
||||
std::function<void()> onChanged) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (started_) return;
|
||||
started_ = true;
|
||||
db_ = &db;
|
||||
timezone_ = timezone;
|
||||
onChanged_ = std::move(onChanged);
|
||||
licenseKey_ = db.getKV(db::KV_LICENSE_KEY);
|
||||
enabled_ = true; // config supplies the toggle via setEnabled()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (started_) return;
|
||||
started_ = true;
|
||||
db_ = &db;
|
||||
timezone_ = timezone;
|
||||
onChanged_ = std::move(onChanged);
|
||||
licenseKey_ = db.getKV(db::KV_LICENSE_KEY);
|
||||
enabled_ = true; // config supplies the toggle via setEnabled()
|
||||
}
|
||||
|
||||
// Offline first: load any cached payload immediately.
|
||||
// Offline first: load any cached payload immediately. Called outside the
|
||||
// lock because loadCache() acquires mutex_ itself; holding it here would
|
||||
// self-deadlock on the non-recursive mutex when a cache file exists.
|
||||
loadCache();
|
||||
|
||||
stop_.store(false);
|
||||
|
||||
Reference in New Issue
Block a user