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