[flang] Avoid potential deadlock in CloseAll()

When closing all open units, don't hold the unit map lock
over the actual close operations; if one of those aborts,
CloseAll() may be called and then deadlock.

Differential Review: https://reviews.llvm.org/D115184
This commit is contained in:
Peter Klausler 2021-12-04 11:30:01 -08:00
parent 622d689480
commit c84616c3b3
1 changed files with 16 additions and 7 deletions

View File

@ -52,15 +52,24 @@ void UnitMap::DestroyClosed(ExternalFileUnit &unit) {
}
void UnitMap::CloseAll(IoErrorHandler &handler) {
CriticalSection critical{lock_};
for (int j{0}; j < buckets_; ++j) {
while (Chain * p{bucket_[j].get()}) {
bucket_[j].swap(p->next); // pops p from head of list
p->unit.CloseUnit(CloseStatus::Keep, handler);
p->unit.~ExternalFileUnit();
FreeMemory(p);
// Extract units from the map so they can be closed
// without holding lock_.
OwningPtr<Chain> closeList;
{
CriticalSection critical{lock_};
for (int j{0}; j < buckets_; ++j) {
while (Chain * p{bucket_[j].get()}) {
bucket_[j].swap(p->next); // pops p from head of bucket list
closeList.swap(p->next); // pushes p to closeList
}
}
}
while (Chain * p{closeList.get()}) {
closeList.swap(p->next); // pops p from head of closeList
p->unit.CloseUnit(CloseStatus::Keep, handler);
p->unit.~ExternalFileUnit();
FreeMemory(p);
}
}
void UnitMap::FlushAll(IoErrorHandler &handler) {