use_dll: fixes to parallel compilation
— No longer call std::exit() from threads when compilation fails, that function is marked as not thread-safe under GNU/Linux; and it leads to deadlocks under Windows. Rather store the list of failed objects, and exit with a message and an error code from the main thread when that list is not empty at the end of preprocessing. – Fix the condition used for waiting until all compilation threads finish; checking that the queue is empty is not enough, since a compilation may be ongoing. So also track objects whose compilation is ongoing.master
parent
f349e22f4c
commit
21fcfa7758
|
@ -44,7 +44,7 @@
|
||||||
condition_variable_any ModelTree::mex_compilation_cv;
|
condition_variable_any ModelTree::mex_compilation_cv;
|
||||||
mutex ModelTree::mex_compilation_mut;
|
mutex ModelTree::mex_compilation_mut;
|
||||||
vector<tuple<filesystem::path, set<filesystem::path>, string>> ModelTree::mex_compilation_queue;
|
vector<tuple<filesystem::path, set<filesystem::path>, string>> ModelTree::mex_compilation_queue;
|
||||||
set<filesystem::path> ModelTree::mex_compilation_done;
|
set<filesystem::path> ModelTree::mex_compilation_ongoing, ModelTree::mex_compilation_done, ModelTree::mex_compilation_failed;
|
||||||
vector<jthread> ModelTree::mex_compilation_workers;
|
vector<jthread> ModelTree::mex_compilation_workers;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1955,6 +1955,7 @@ ModelTree::initializeMEXCompilationWorkers(int numworkers)
|
||||||
output = get<0>(*it);
|
output = get<0>(*it);
|
||||||
cmd = get<2>(*it);
|
cmd = get<2>(*it);
|
||||||
mex_compilation_queue.erase(it);
|
mex_compilation_queue.erase(it);
|
||||||
|
mex_compilation_ongoing.insert(output);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1964,12 +1965,12 @@ ModelTree::initializeMEXCompilationWorkers(int numworkers)
|
||||||
if (mex_compilation_cv.wait(lk, stoken, pick_job))
|
if (mex_compilation_cv.wait(lk, stoken, pick_job))
|
||||||
{
|
{
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
if (system(cmd.c_str()))
|
int r { system(cmd.c_str()) };
|
||||||
{
|
|
||||||
cerr << "Compilation failed" << endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
lk.lock();
|
lk.lock();
|
||||||
|
mex_compilation_ongoing.erase(output);
|
||||||
|
if (r)
|
||||||
|
mex_compilation_failed.insert(output);
|
||||||
|
else
|
||||||
mex_compilation_done.insert(output);
|
mex_compilation_done.insert(output);
|
||||||
/* The object just compiled may be a prerequisite for several
|
/* The object just compiled may be a prerequisite for several
|
||||||
other objects, so notify all waiting workers. Also needed to
|
other objects, so notify all waiting workers. Also needed to
|
||||||
|
@ -1984,7 +1985,18 @@ void
|
||||||
ModelTree::waitForMEXCompilationWorkers()
|
ModelTree::waitForMEXCompilationWorkers()
|
||||||
{
|
{
|
||||||
unique_lock<mutex> lk {mex_compilation_mut};
|
unique_lock<mutex> lk {mex_compilation_mut};
|
||||||
mex_compilation_cv.wait(lk, [] { return mex_compilation_queue.empty(); });
|
mex_compilation_cv.wait(lk, [] {
|
||||||
|
return (mex_compilation_queue.empty() && mex_compilation_ongoing.empty())
|
||||||
|
|| !mex_compilation_failed.empty(); });
|
||||||
|
if (!mex_compilation_failed.empty())
|
||||||
|
{
|
||||||
|
cerr << "Compilation failed for: ";
|
||||||
|
for (const auto &p : mex_compilation_failed)
|
||||||
|
cerr << p.string() << " ";
|
||||||
|
cerr << endl;
|
||||||
|
lk.unlock(); // So that threads can process their stoken
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -439,8 +439,12 @@ private:
|
||||||
/* Object/MEX files waiting to be compiled (with their prerequisites as 2nd
|
/* Object/MEX files waiting to be compiled (with their prerequisites as 2nd
|
||||||
element and compilation command as the 3rd element) */
|
element and compilation command as the 3rd element) */
|
||||||
static vector<tuple<filesystem::path, set<filesystem::path>, string>> mex_compilation_queue;
|
static vector<tuple<filesystem::path, set<filesystem::path>, string>> mex_compilation_queue;
|
||||||
// Object/MEX files already compiled
|
// Object/MEX files in the process of being compiled
|
||||||
|
static set<filesystem::path> mex_compilation_ongoing;
|
||||||
|
// Object/MEX files already compiled successfully
|
||||||
static set<filesystem::path> mex_compilation_done;
|
static set<filesystem::path> mex_compilation_done;
|
||||||
|
// Object/MEX files whose compilation failed
|
||||||
|
static set<filesystem::path> mex_compilation_failed;
|
||||||
|
|
||||||
/* Compute a pseudo-Jacobian whose all elements are either zero or one,
|
/* Compute a pseudo-Jacobian whose all elements are either zero or one,
|
||||||
depending on whether the variable symbolically appears in the equation. If
|
depending on whether the variable symbolically appears in the equation. If
|
||||||
|
|
Loading…
Reference in New Issue