comparison framework/Align.cpp @ 718:464fed3096f5

Avoid deadlock when process finishes immediately (so alignmentProgramFinished is called from waitForStarted while mutex already held)
author Chris Cannam
date Thu, 31 Oct 2019 11:28:35 +0000
parents d2e8e9788cd4
children
comparison
equal deleted inserted replaced
717:d2e8e9788cd4 718:464fed3096f5
485 ModelId referenceId, 485 ModelId referenceId,
486 ModelId otherId, 486 ModelId otherId,
487 QString program, 487 QString program,
488 QString &error) 488 QString &error)
489 { 489 {
490 QMutexLocker locker (&m_mutex);
491
492 // Run an external program, passing to it paths to the main 490 // Run an external program, passing to it paths to the main
493 // model's audio file and the new model's audio file. It returns 491 // model's audio file and the new model's audio file. It returns
494 // the path in CSV form through stdout. 492 // the path in CSV form through stdout.
495 493
496 auto reference = ModelById::getAs<ReadOnlyWaveFileModel>(referenceId); 494 auto reference = ModelById::getAs<ReadOnlyWaveFileModel>(referenceId);
517 if (refPath == "" || otherPath == "") { 515 if (refPath == "" || otherPath == "") {
518 error = "Failed to find local filepath for wave-file model"; 516 error = "Failed to find local filepath for wave-file model";
519 return false; 517 return false;
520 } 518 }
521 519
522 auto alignmentModel = 520 QProcess *process = nullptr;
523 std::make_shared<AlignmentModel>(referenceId, otherId, ModelId()); 521 ModelId alignmentModelId = {};
524 auto alignmentModelId = ModelById::add(alignmentModel); 522
525 other->setAlignment(alignmentModelId); 523 {
526 524 QMutexLocker locker (&m_mutex);
527 QProcess *process = new QProcess; 525
528 process->setProcessChannelMode(QProcess::ForwardedErrorChannel); 526 auto alignmentModel =
527 std::make_shared<AlignmentModel>(referenceId, otherId, ModelId());
528
529 alignmentModelId = ModelById::add(alignmentModel);
530 other->setAlignment(alignmentModelId);
531
532 process = new QProcess;
533 process->setProcessChannelMode(QProcess::ForwardedErrorChannel);
534
535 connect(process,
536 SIGNAL(finished(int, QProcess::ExitStatus)),
537 this,
538 SLOT(alignmentProgramFinished(int, QProcess::ExitStatus)));
539
540 m_pendingProcesses[process] = alignmentModelId;
541 }
529 542
530 QStringList args; 543 QStringList args;
531 args << refPath << otherPath; 544 args << refPath << otherPath;
532
533 connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
534 this, SLOT(alignmentProgramFinished(int, QProcess::ExitStatus)));
535
536 m_pendingProcesses[process] = alignmentModelId;
537 545
538 SVCERR << "Align::alignModelViaProgram: Starting program \"" 546 SVCERR << "Align::alignModelViaProgram: Starting program \""
539 << program << "\" with args: "; 547 << program << "\" with args: ";
540 for (auto a: args) { 548 for (auto a: args) {
541 SVCERR << "\"" << a << "\" "; 549 SVCERR << "\"" << a << "\" ";
544 552
545 process->start(program, args); 553 process->start(program, args);
546 554
547 bool success = process->waitForStarted(); 555 bool success = process->waitForStarted();
548 556
549 if (!success) { 557 {
550 SVCERR << "ERROR: Align::alignModelViaProgram: Program did not start" 558 QMutexLocker locker(&m_mutex);
551 << endl; 559
552 error = "Alignment program \"" + program + "\" could not be executed"; 560 if (!success) {
553 m_pendingProcesses.erase(process); 561
554 other->setAlignment({}); 562 SVCERR << "ERROR: Align::alignModelViaProgram: "
555 ModelById::release(alignmentModelId); 563 << "Program did not start" << endl;
556 delete process; 564 error = "Alignment program \"" + program + "\" did not start";
557 } else { 565
558 doc->addNonDerivedModel(alignmentModelId); 566 m_pendingProcesses.erase(process);
567 other->setAlignment({});
568 ModelById::release(alignmentModelId);
569 delete process;
570
571 } else {
572 doc->addNonDerivedModel(alignmentModelId);
573 }
559 } 574 }
560 575
561 return success; 576 return success;
562 } 577 }
563 578