diff --git a/flang/runtime/lock.h b/flang/runtime/lock.h --- a/flang/runtime/lock.h +++ b/flang/runtime/lock.h @@ -41,9 +41,24 @@ void Take() { while (pthread_mutex_lock(&mutex_)) { } + holder_ = pthread_self(); + isBusy_ = true; + } + bool TakeIfNoDeadlock() { + if (isBusy_) { + auto thisThread{pthread_self()}; + if (pthread_equal(thisThread, holder_)) { + return false; + } + } + Take(); + return true; } bool Try() { return pthread_mutex_trylock(&mutex_) == 0; } - void Drop() { pthread_mutex_unlock(&mutex_); } + void Drop() { + isBusy_ = false; + pthread_mutex_unlock(&mutex_); + } #elif defined(_WIN32) Lock() { InitializeCriticalSection(&cs_); } ~Lock() { DeleteCriticalSection(&cs_); } @@ -66,6 +81,8 @@ private: #if USE_PTHREADS pthread_mutex_t mutex_{}; + volatile bool isBusy_{false}; + volatile pthread_t holder_; #elif defined(_WIN32) CRITICAL_SECTION cs_; #else diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -71,17 +71,14 @@ template IoStatementState &BeginIoStatement(const Terminator &terminator, X &&...xs) { - bool alreadyBusy{false}; - { - CriticalSection critical{lock_}; - alreadyBusy = isBusy_; - isBusy_ = true; // cleared in EndIoStatement() - } - if (alreadyBusy) { - terminator.Crash("Could not acquire exclusive lock on unit %d, perhaps " - "due to an attempt to perform recursive I/O", - unitNumber_); + // Take lock_ and hold it until EndIoStatement(). +#if USE_PTHREADS + if (!lock_.TakeIfNoDeadlock()) { + terminator.Crash("Recursive I/O attempted on unit %d", unitNumber_); } +#else + lock_.Take(); +#endif A &state{u_.emplace(std::forward(xs)...)}; if constexpr (!std::is_same_v) { state.mutableModes() = ConnectionState::modes; @@ -137,8 +134,6 @@ std::int32_t ReadHeaderOrFooter(std::int64_t frameOffset); Lock lock_; - // TODO: replace with a thread ID - bool isBusy_{false}; // under lock_ int unitNumber_{-1}; Direction direction_{Direction::Output}; diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -714,8 +714,7 @@ void ExternalFileUnit::EndIoStatement() { io_.reset(); u_.emplace(); - CriticalSection critical{lock_}; - isBusy_ = false; + lock_.Drop(); } void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(