1 //===- Filesystem.cpp -----------------------------------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains a few utility functions to handle files. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "Filesystem.h" 15 #include "Config.h" 16 #include "lld/Common/Threads.h" 17 #include "llvm/Config/llvm-config.h" 18 #include "llvm/Support/FileOutputBuffer.h" 19 #include "llvm/Support/FileSystem.h" 20 #if LLVM_ON_UNIX 21 #include <unistd.h> 22 #endif 23 #include <thread> 24 25 using namespace llvm; 26 27 using namespace lld; 28 using namespace lld::elf; 29 30 // Removes a given file asynchronously. This is a performance hack, 31 // so remove this when operating systems are improved. 32 // 33 // On Linux (and probably on other Unix-like systems), unlink(2) is a 34 // noticeably slow system call. As of 2016, unlink takes 250 35 // milliseconds to remove a 1 GB file on ext4 filesystem on my machine. 36 // 37 // To create a new result file, we first remove existing file. So, if 38 // you repeatedly link a 1 GB program in a regular compile-link-debug 39 // cycle, every cycle wastes 250 milliseconds only to remove a file. 40 // Since LLD can link a 1 GB binary in about 5 seconds, that waste 41 // actually counts. 42 // 43 // This function spawns a background thread to remove the file. 44 // The calling thread returns almost immediately. 45 void elf::unlinkAsync(StringRef Path) { 46 // Removing a file is async on windows. 47 #if defined(LLVM_ON_WIN32) 48 sys::fs::remove(Path); 49 #else 50 if (!ThreadsEnabled || !sys::fs::exists(Path) || 51 !sys::fs::is_regular_file(Path)) 52 return; 53 54 // We cannot just remove path from a different thread because we are now going 55 // to create path as a new file. 56 // Instead we open the file and unlink it on this thread. The unlink is fast 57 // since the open fd guarantees that it is not removing the last reference. 58 int FD; 59 std::error_code EC = sys::fs::openFileForRead(Path, FD); 60 sys::fs::remove(Path); 61 62 // close and therefore remove TempPath in background. 63 if (!EC) 64 std::thread([=] { ::close(FD); }).detach(); 65 #endif 66 } 67 68 // Simulate file creation to see if Path is writable. 69 // 70 // Determining whether a file is writable or not is amazingly hard, 71 // and after all the only reliable way of doing that is to actually 72 // create a file. But we don't want to do that in this function 73 // because LLD shouldn't update any file if it will end in a failure. 74 // We also don't want to reimplement heuristics to determine if a 75 // file is writable. So we'll let FileOutputBuffer do the work. 76 // 77 // FileOutputBuffer doesn't touch a desitnation file until commit() 78 // is called. We use that class without calling commit() to predict 79 // if the given file is writable. 80 std::error_code elf::tryCreateFile(StringRef Path) { 81 if (Path.empty()) 82 return std::error_code(); 83 if (Path == "-") 84 return std::error_code(); 85 return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError()); 86 } 87