xref: /openbsd-src/gnu/llvm/lld/Common/Filesystem.cpp (revision bb684c341a3e51760883ccd79a12f6a8e98ab5b9)
1ece8a530Spatrick //===- Filesystem.cpp -----------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick //
9ece8a530Spatrick // This file contains a few utility functions to handle files.
10ece8a530Spatrick //
11ece8a530Spatrick //===----------------------------------------------------------------------===//
12ece8a530Spatrick 
13ece8a530Spatrick #include "lld/Common/Filesystem.h"
14ece8a530Spatrick #include "llvm/Config/llvm-config.h"
15ece8a530Spatrick #include "llvm/Support/FileOutputBuffer.h"
16ece8a530Spatrick #include "llvm/Support/FileSystem.h"
17*bb684c34Spatrick #include "llvm/Support/Parallel.h"
18*bb684c34Spatrick #include "llvm/Support/Path.h"
19ece8a530Spatrick #if LLVM_ON_UNIX
20ece8a530Spatrick #include <unistd.h>
21ece8a530Spatrick #endif
22ece8a530Spatrick #include <thread>
23ece8a530Spatrick 
24ece8a530Spatrick using namespace llvm;
25ece8a530Spatrick using namespace lld;
26ece8a530Spatrick 
27ece8a530Spatrick // Removes a given file asynchronously. This is a performance hack,
28ece8a530Spatrick // so remove this when operating systems are improved.
29ece8a530Spatrick //
30ece8a530Spatrick // On Linux (and probably on other Unix-like systems), unlink(2) is a
31ece8a530Spatrick // noticeably slow system call. As of 2016, unlink takes 250
32ece8a530Spatrick // milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
33ece8a530Spatrick //
34ece8a530Spatrick // To create a new result file, we first remove existing file. So, if
35ece8a530Spatrick // you repeatedly link a 1 GB program in a regular compile-link-debug
36ece8a530Spatrick // cycle, every cycle wastes 250 milliseconds only to remove a file.
37ece8a530Spatrick // Since LLD can link a 1 GB binary in about 5 seconds, that waste
38ece8a530Spatrick // actually counts.
39ece8a530Spatrick //
40ece8a530Spatrick // This function spawns a background thread to remove the file.
41ece8a530Spatrick // The calling thread returns almost immediately.
unlinkAsync(StringRef path)42ece8a530Spatrick void lld::unlinkAsync(StringRef path) {
43*bb684c34Spatrick   if (!sys::fs::exists(path) || !sys::fs::is_regular_file(path))
44*bb684c34Spatrick     return;
45*bb684c34Spatrick 
46ece8a530Spatrick // Removing a file is async on windows.
47ece8a530Spatrick #if defined(_WIN32)
48*bb684c34Spatrick   // On Windows co-operative programs can be expected to open LLD's
49*bb684c34Spatrick   // output in FILE_SHARE_DELETE mode. This allows us to delete the
50*bb684c34Spatrick   // file (by moving it to a temporary filename and then deleting
51*bb684c34Spatrick   // it) so that we can link another output file that overwrites
52*bb684c34Spatrick   // the existing file, even if the current file is in use.
53*bb684c34Spatrick   //
54*bb684c34Spatrick   // This is done on a best effort basis - we do not error if the
55*bb684c34Spatrick   // operation fails. The consequence is merely that the user
56*bb684c34Spatrick   // experiences an inconvenient work-flow.
57*bb684c34Spatrick   //
58*bb684c34Spatrick   // The code here allows LLD to work on all versions of Windows.
59*bb684c34Spatrick   // However, at Windows 10 1903 it seems that the behavior of
60*bb684c34Spatrick   // Windows has changed, so that we could simply delete the output
61*bb684c34Spatrick   // file. This code should be simplified once support for older
62*bb684c34Spatrick   // versions of Windows is dropped.
63*bb684c34Spatrick   //
64*bb684c34Spatrick   // Warning: It seems that the WINVER and _WIN32_WINNT preprocessor
65*bb684c34Spatrick   // defines affect the behavior of the Windows versions of the calls
66*bb684c34Spatrick   // we are using here. If this code stops working this is worth
67*bb684c34Spatrick   // bearing in mind.
68*bb684c34Spatrick   SmallString<128> tmpName;
69*bb684c34Spatrick   if (!sys::fs::createUniqueFile(path + "%%%%%%%%.tmp", tmpName)) {
70*bb684c34Spatrick     if (!sys::fs::rename(path, tmpName))
71*bb684c34Spatrick       path = tmpName;
72*bb684c34Spatrick     else
73*bb684c34Spatrick       sys::fs::remove(tmpName);
74*bb684c34Spatrick   }
75ece8a530Spatrick   sys::fs::remove(path);
76ece8a530Spatrick #else
77*bb684c34Spatrick   if (parallel::strategy.ThreadsRequested == 1)
78ece8a530Spatrick     return;
79ece8a530Spatrick 
80ece8a530Spatrick   // We cannot just remove path from a different thread because we are now going
81ece8a530Spatrick   // to create path as a new file.
82ece8a530Spatrick   // Instead we open the file and unlink it on this thread. The unlink is fast
83ece8a530Spatrick   // since the open fd guarantees that it is not removing the last reference.
84ece8a530Spatrick   int fd;
85ece8a530Spatrick   std::error_code ec = sys::fs::openFileForRead(path, fd);
86ece8a530Spatrick   sys::fs::remove(path);
87ece8a530Spatrick 
88ece8a530Spatrick   if (ec)
89ece8a530Spatrick     return;
90ece8a530Spatrick 
91ece8a530Spatrick   // close and therefore remove TempPath in background.
92ece8a530Spatrick   std::mutex m;
93ece8a530Spatrick   std::condition_variable cv;
94ece8a530Spatrick   bool started = false;
95ece8a530Spatrick   std::thread([&, fd] {
96ece8a530Spatrick     {
97ece8a530Spatrick       std::lock_guard<std::mutex> l(m);
98ece8a530Spatrick       started = true;
99ece8a530Spatrick       cv.notify_all();
100ece8a530Spatrick     }
101ece8a530Spatrick     ::close(fd);
102ece8a530Spatrick   }).detach();
103ece8a530Spatrick 
104ece8a530Spatrick   // GLIBC 2.26 and earlier have race condition that crashes an entire process
105ece8a530Spatrick   // if the main thread calls exit(2) while other thread is starting up.
106ece8a530Spatrick   std::unique_lock<std::mutex> l(m);
107ece8a530Spatrick   cv.wait(l, [&] { return started; });
108ece8a530Spatrick #endif
109ece8a530Spatrick }
110ece8a530Spatrick 
111ece8a530Spatrick // Simulate file creation to see if Path is writable.
112ece8a530Spatrick //
113ece8a530Spatrick // Determining whether a file is writable or not is amazingly hard,
114ece8a530Spatrick // and after all the only reliable way of doing that is to actually
115ece8a530Spatrick // create a file. But we don't want to do that in this function
116ece8a530Spatrick // because LLD shouldn't update any file if it will end in a failure.
117ece8a530Spatrick // We also don't want to reimplement heuristics to determine if a
118ece8a530Spatrick // file is writable. So we'll let FileOutputBuffer do the work.
119ece8a530Spatrick //
120ece8a530Spatrick // FileOutputBuffer doesn't touch a destination file until commit()
121ece8a530Spatrick // is called. We use that class without calling commit() to predict
122ece8a530Spatrick // if the given file is writable.
tryCreateFile(StringRef path)123ece8a530Spatrick std::error_code lld::tryCreateFile(StringRef path) {
124ece8a530Spatrick   if (path.empty())
125ece8a530Spatrick     return std::error_code();
126ece8a530Spatrick   if (path == "-")
127ece8a530Spatrick     return std::error_code();
128ece8a530Spatrick   return errorToErrorCode(FileOutputBuffer::create(path, 1).takeError());
129ece8a530Spatrick }
130