[flang-commits] [flang] 00a1c6d - [flang] Restore old unit locking behavior

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu Dec 8 08:34:55 PST 2022


Author: Peter Klausler
Date: 2022-12-08T08:34:46-08:00
New Revision: 00a1c6d036328db46c20cda88edb020ddbda05b4

URL: https://github.com/llvm/llvm-project/commit/00a1c6d036328db46c20cda88edb020ddbda05b4
DIFF: https://github.com/llvm/llvm-project/commit/00a1c6d036328db46c20cda88edb020ddbda05b4.diff

LOG: [flang] Restore old unit locking behavior

Rework  the recursive I/O error check on I/O units so that
threads again hold a lock on a unit throughout an I/O statement.
Add an API to the runtime's Lock class implementation for pthreads
to allow detection of solf-deadlock without depending on EDEADLK
or recursive mutexes.

This should fix I/O from OpenMP threads.

Differential Revision: https://reviews.llvm.org/D139477

Added: 
    

Modified: 
    flang/runtime/lock.h
    flang/runtime/unit.cpp
    flang/runtime/unit.h

Removed: 
    


################################################################################
diff  --git a/flang/runtime/lock.h b/flang/runtime/lock.h
index 7af1ab89758ed..5fdcf4745c21c 100644
--- a/flang/runtime/lock.h
+++ b/flang/runtime/lock.h
@@ -41,9 +41,24 @@ class Lock {
   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 @@ class Lock {
 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.cpp b/flang/runtime/unit.cpp
index 357d237c63e43..092a0a27b5c23 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -714,8 +714,7 @@ bool ExternalFileUnit::SetDirectRec(
 void ExternalFileUnit::EndIoStatement() {
   io_.reset();
   u_.emplace<std::monostate>();
-  CriticalSection critical{lock_};
-  isBusy_ = false;
+  lock_.Drop();
 }
 
 void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(

diff  --git a/flang/runtime/unit.h b/flang/runtime/unit.h
index 9f2b0bf3a9861..c49f479830338 100644
--- a/flang/runtime/unit.h
+++ b/flang/runtime/unit.h
@@ -71,17 +71,14 @@ class ExternalFileUnit : public ConnectionState,
 
   template <typename A, typename... X>
   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<A>(std::forward<X>(xs)...)};
     if constexpr (!std::is_same_v<A, OpenStatementState>) {
       state.mutableModes() = ConnectionState::modes;
@@ -137,8 +134,6 @@ class ExternalFileUnit : public ConnectionState,
   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};


        


More information about the flang-commits mailing list