OSDN Git Service

[Support/LockFileManager] Make the LockFileManager more robust against races.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 6 Mar 2014 17:37:10 +0000 (17:37 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 6 Mar 2014 17:37:10 +0000 (17:37 +0000)
There was a race where:
- The LockFileManager tries to own the lock file and fails.
- The other owner then releases and removes the lock file.
- The LockFileManager tries to read the owner info from the lock file but fails now.

In such a case have LockFileManager try to get ownership again, instead of error'ing out.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203138 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Support/LockFileManager.cpp

index acb310e..957f2fd 100644 (file)
@@ -115,25 +115,42 @@ LockFileManager::LockFileManager(StringRef FileName)
     }
   }
 
-  // Create a symbolic link from the lock file name. If this succeeds, we're done.
-  // Note that we are using symbolic link because hard links are not supported
-  // by all filesystems.
-  error_code EC
-    = sys::fs::create_symbolic_link(UniqueLockFileName.str(),
-                                      LockFileName.str());
-  if (EC == errc::success)
-    return;
+  while (1) {
+    // Create a symbolic link from the lock file name. If this succeeds, we're
+    // done. Note that we are using symbolic link because hard links are not
+    // supported by all filesystems.
+    error_code EC
+      = sys::fs::create_symbolic_link(UniqueLockFileName.str(),
+                                        LockFileName.str());
+    if (EC == errc::success)
+      return;
 
-  // Someone else managed to create the lock file first. Wipe out our unique
-  // lock file (it's useless now) and read the process ID from the lock file.
-  sys::fs::remove(UniqueLockFileName.str());
-  if ((Owner = readLockFile(LockFileName)))
-    return;
+    if (EC != errc::file_exists) {
+      Error = EC;
+      return;
+    }
 
-  // There is a lock file that nobody owns; try to clean it up and report
-  // an error.
-  sys::fs::remove(LockFileName.str());
-  Error = EC;
+    // Someone else managed to create the lock file first. Read the process ID
+    // from the lock file.
+    if ((Owner = readLockFile(LockFileName))) {
+      // Wipe out our unique lock file (it's useless now)
+      sys::fs::remove(UniqueLockFileName.str());
+      return;
+    }
+
+    if (!sys::fs::exists(LockFileName.str())) {
+      // The previous owner released the lock file before we could read it.
+      // Try to get ownership again.
+      continue;
+    }
+
+    // There is a lock file that nobody owns; try to clean it up and get
+    // ownership.
+    if ((EC = sys::fs::remove(LockFileName.str()))) {
+      Error = EC;
+      return;
+    }
+  }
 }
 
 LockFileManager::LockFileState LockFileManager::getState() const {