llvm.org GIT mirror llvm / ec6f9b0
Use TempFile in the implementation of LockFileManager. This move some of the complexity over to the lower level TempFile. It also makes it a bit more explicit where errors are ignored since we now have a call to consumeError. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@318550 91177308-0d34-0410-b5e6-96231b3b80d8 Rafael Espindola 2 years ago
2 changed file(s) with 42 addition(s) and 58 deletion(s). Raw diff Collapse all Expand all
1010
1111 #include "llvm/ADT/Optional.h"
1212 #include "llvm/ADT/SmallString.h"
13 #include "llvm/Support/FileSystem.h"
1314 #include
1415 #include // for std::pair
1516
5253 private:
5354 SmallString<128> FileName;
5455 SmallString<128> LockFileName;
55 SmallString<128> UniqueLockFileName;
56 Optional UniqueLockFile;
5657
5758 Optional > Owner;
5859 std::error_code ErrorCode;
122122
123123 namespace {
124124
125 /// An RAII helper object ensure that the unique lock file is removed.
126 ///
127 /// Ensures that if there is an error or a signal before we finish acquiring the
128 /// lock, the unique file will be removed. And if we successfully take the lock,
129 /// the signal handler is left in place so that signals while the lock is held
130 /// will remove the unique lock file. The caller should ensure there is a
131 /// matching call to sys::DontRemoveFileOnSignal when the lock is released.
132 class RemoveUniqueLockFileOnSignal {
133 StringRef Filename;
134 bool RemoveImmediately;
125 /// An RAII helper object for cleanups.
126 class RAIICleanup {
127 std::function Fn;
128 bool Canceled = false;
129
135130 public:
136 RemoveUniqueLockFileOnSignal(StringRef Name)
137 : Filename(Name), RemoveImmediately(true) {
138 sys::RemoveFileOnSignal(Filename, nullptr);
139 }
140
141 ~RemoveUniqueLockFileOnSignal() {
142 if (!RemoveImmediately) {
143 // Leave the signal handler enabled. It will be removed when the lock is
144 // released.
145 return;
146 }
147 sys::fs::remove(Filename);
148 sys::DontRemoveFileOnSignal(Filename);
149 }
150
151 void lockAcquired() { RemoveImmediately = false; }
131 RAIICleanup(std::function Fn) : Fn(Fn) {}
132
133 ~RAIICleanup() {
134 if (Canceled)
135 return;
136 Fn();
137 }
138
139 void cancel() { Canceled = true; }
152140 };
153141
154142 } // end anonymous namespace
171159 return;
172160
173161 // Create a lock file that is unique to this instance.
174 UniqueLockFileName = LockFileName;
175 UniqueLockFileName += "-%%%%%%%%";
176 int UniqueLockFileID;
177 if (std::error_code EC = sys::fs::createUniqueFile(
178 UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) {
179 std::string S("failed to create unique file ");
180 S.append(UniqueLockFileName.str());
162 Expected Temp =
163 sys::fs::TempFile::create(LockFileName + "-%%%%%%%%");
164 if (!Temp) {
165 std::error_code EC = errorToErrorCode(Temp.takeError());
166 std::string S("failed to create unique file with prefix ");
167 S.append(LockFileName.str());
181168 setError(EC, S);
182169 return;
183170 }
171 UniqueLockFile = std::move(*Temp);
172
173 // Make sure we discard the temporary file on exit.
174 RAIICleanup RemoveTempFile([&]() {
175 if (Error E = UniqueLockFile->discard())
176 setError(errorToErrorCode(std::move(E)));
177 });
184178
185179 // Write our process ID to our unique lock file.
186180 {
190184 return;
191185 }
192186
193 raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
187 raw_fd_ostream Out(UniqueLockFile->FD, /*shouldClose=*/false);
194188 Out << HostID << ' ';
195189 #if LLVM_ON_UNIX
196190 Out << getpid();
197191 #else
198192 Out << "1";
199193 #endif
200 Out.close();
194 Out.flush();
201195
202196 if (Out.has_error()) {
203197 // We failed to write out PID, so report the error, remove the
204198 // unique lock file, and fail.
205199 std::string S("failed to write to ");
206 S.append(UniqueLockFileName.str());
200 S.append(UniqueLockFile->TmpName);
207201 setError(Out.error(), S);
208 sys::fs::remove(UniqueLockFileName);
209 return;
210 }
211 }
212
213 // Clean up the unique file on signal, which also releases the lock if it is
214 // held since the .lock symlink will point to a nonexistent file.
215 RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName);
202 return;
203 }
204 }
216205
217206 while (true) {
218207 // Create a link from the lock file name. If this succeeds, we're done.
219208 std::error_code EC =
220 sys::fs::create_link(UniqueLockFileName, LockFileName);
209 sys::fs::create_link(UniqueLockFile->TmpName, LockFileName);
221210 if (!EC) {
222 RemoveUniqueFile.lockAcquired();
211 RemoveTempFile.cancel();
223212 return;
224213 }
225214
226215 if (EC != errc::file_exists) {
227216 std::string S("failed to create link ");
228217 raw_string_ostream OSS(S);
229 OSS << LockFileName.str() << " to " << UniqueLockFileName.str();
218 OSS << LockFileName.str() << " to " << UniqueLockFile->TmpName;
230219 setError(EC, OSS.str());
231220 return;
232221 }
233222
234223 // Someone else managed to create the lock file first. Read the process ID
235224 // from the lock file.
236 if ((Owner = readLockFile(LockFileName))) {
237 // Wipe out our unique lock file (it's useless now)
238 sys::fs::remove(UniqueLockFileName);
239 return;
240 }
225 if ((Owner = readLockFile(LockFileName)))
226 return; // RemoveTempFile will delete out our unique lock file.
241227
242228 if (!sys::fs::exists(LockFileName)) {
243229 // The previous owner released the lock file before we could read it.
249235 // ownership.
250236 if ((EC = sys::fs::remove(LockFileName))) {
251237 std::string S("failed to remove lockfile ");
252 S.append(UniqueLockFileName.str());
238 S.append(LockFileName.str());
253239 setError(EC, S);
254240 return;
255241 }
284270
285271 // Since we own the lock, remove the lock file and our own unique lock file.
286272 sys::fs::remove(LockFileName);
287 sys::fs::remove(UniqueLockFileName);
288 // The unique file is now gone, so remove it from the signal handler. This
289 // matches a sys::RemoveFileOnSignal() in LockFileManager().
290 sys::DontRemoveFileOnSignal(UniqueLockFileName);
273 consumeError(UniqueLockFile->discard());
291274 }
292275
293276 LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {