From 9b55e92a7fce678434a4d6ff4e39e098a2062bba Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 24 Mar 2017 00:15:16 +0000 Subject: [PATCH] Move a few functions to a new file Filesystem.{cpp,h}. llvm-svn: 298667 --- lld/ELF/CMakeLists.txt | 1 + lld/ELF/Driver.cpp | 24 ++----------- lld/ELF/Filesystem.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++ lld/ELF/Filesystem.h | 22 ++++++++++++ lld/ELF/Writer.cpp | 38 +------------------- 5 files changed, 105 insertions(+), 59 deletions(-) create mode 100644 lld/ELF/Filesystem.cpp create mode 100644 lld/ELF/Filesystem.h diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index 02888b890edd..a16e1b891bf0 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -11,6 +11,7 @@ add_lld_library(lldELF DriverUtils.cpp EhFrame.cpp Error.cpp + Filesystem.cpp GdbIndex.cpp ICF.cpp InputFiles.cpp diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 3445edfa0c7c..b0744478eeaf 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -26,6 +26,7 @@ #include "Driver.h" #include "Config.h" #include "Error.h" +#include "Filesystem.h" #include "ICF.h" #include "InputFiles.h" #include "InputSection.h" @@ -43,7 +44,6 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" @@ -846,26 +846,6 @@ static uint64_t getImageBase(opt::InputArgList &Args) { return V; } -// Returns true if a given file seems to be writable. -// -// Determining whether a file is writable or not is amazingly hard, -// and after all the only reliable way of doing that is to actually -// create a file. But we don't want to do that in this function -// because LLD shouldn't update any file if it will end in a failure. -// We also don't want to reimplement heuristics. So we'll let -// FileOutputBuffer do the work. -// -// FileOutputBuffer doesn't touch a desitnation file until commit() -// is called. We use that class without calling commit() to predict -// if the given file is writable. -static bool isWritable(StringRef Path) { - if (auto EC = FileOutputBuffer::create(Path, 1).getError()) { - error("cannot open output file " + Path + ": " + EC.message()); - return false; - } - return true; -} - // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template void LinkerDriver::link(opt::InputArgList &Args) { @@ -883,7 +863,7 @@ template void LinkerDriver::link(opt::InputArgList &Args) { // Fail early if the output file is not writable. If a user has a long link, // e.g. due to a large LTO link, they do not wish to run it and find that it // failed because there was a mistake in their command-line. - if (!isWritable(Config->OutputFile)) + if (!isFileWritable(Config->OutputFile)) return; // Use default entry point name if no name was given via the command diff --git a/lld/ELF/Filesystem.cpp b/lld/ELF/Filesystem.cpp new file mode 100644 index 000000000000..d3a965cc78a3 --- /dev/null +++ b/lld/ELF/Filesystem.cpp @@ -0,0 +1,79 @@ +//===- Filesystem.cpp -----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a few utility functions to handle files. +// +//===----------------------------------------------------------------------===// + +#include "Filesystem.h" +#include "Config.h" +#include "Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileOutputBuffer.h" +#include + +using namespace llvm; + +using namespace lld; +using namespace lld::elf; + +// Removes a given file asynchronously. This is a performance hack, +// so remove this when operating systems are improved. +// +// On Linux (and probably on other Unix-like systems), unlink(2) is a +// noticeably slow system call. As of 2016, unlink takes 250 +// milliseconds to remove a 1 GB file on ext4 filesystem on my machine. +// +// To create a new result file, we first remove existing file. So, if +// you repeatedly link a 1 GB program in a regular compile-link-debug +// cycle, every cycle wastes 250 milliseconds only to remove a file. +// Since LLD can link a 1 GB binary in about 5 seconds, that waste +// actually counts. +// +// This function spawns a background thread to call unlink. +// The calling thread returns almost immediately. +void elf::unlinkAsync(StringRef Path) { + if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) + return; + + // First, rename Path to avoid race condition. We cannot remove + // Path from a different thread because we are now going to create + // Path as a new file. If we do that in a different thread, the new + // thread can remove the new file. + SmallString<128> TempPath; + if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) + return; + if (sys::fs::rename(Path, TempPath)) { + sys::fs::remove(TempPath); + return; + } + + // Remove TempPath in background. + std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); +} + +// Returns true if a given file seems to be writable. +// +// Determining whether a file is writable or not is amazingly hard, +// and after all the only reliable way of doing that is to actually +// create a file. But we don't want to do that in this function +// because LLD shouldn't update any file if it will end in a failure. +// We also don't want to reimplement heuristics. So we'll let +// FileOutputBuffer do the work. +// +// FileOutputBuffer doesn't touch a desitnation file until commit() +// is called. We use that class without calling commit() to predict +// if the given file is writable. +bool elf::isFileWritable(StringRef Path) { + if (auto EC = FileOutputBuffer::create(Path, 1).getError()) { + error("cannot open output file " + Path + ": " + EC.message()); + return false; + } + return true; +} diff --git a/lld/ELF/Filesystem.h b/lld/ELF/Filesystem.h new file mode 100644 index 000000000000..7e97cbe634fa --- /dev/null +++ b/lld/ELF/Filesystem.h @@ -0,0 +1,22 @@ +//===- Filesystem.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_FILESYSTEM_H +#define LLD_ELF_FILESYSTEM_H + +#include "lld/Core/LLVM.h" + +namespace lld { +namespace elf { +void unlinkAsync(StringRef Path); +bool isFileWritable(StringRef Path); +} +} + +#endif diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 024d1f24427f..03dc358a3676 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -9,6 +9,7 @@ #include "Writer.h" #include "Config.h" +#include "Filesystem.h" #include "LinkerScript.h" #include "MapFile.h" #include "Memory.h" @@ -21,10 +22,8 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include -#include using namespace llvm; using namespace llvm::ELF; @@ -1747,41 +1746,6 @@ template void Writer::writeHeader() { Sec->writeHeaderTo(++SHdrs); } -// Removes a given file asynchronously. This is a performance hack, -// so remove this when operating systems are improved. -// -// On Linux (and probably on other Unix-like systems), unlink(2) is a -// noticeably slow system call. As of 2016, unlink takes 250 -// milliseconds to remove a 1 GB file on ext4 filesystem on my machine. -// -// To create a new result file, we first remove existing file. So, if -// you repeatedly link a 1 GB program in a regular compile-link-debug -// cycle, every cycle wastes 250 milliseconds only to remove a file. -// Since LLD can link a 1 GB binary in about 5 seconds, that waste -// actually counts. -// -// This function spawns a background thread to call unlink. -// The calling thread returns almost immediately. -static void unlinkAsync(StringRef Path) { - if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) - return; - - // First, rename Path to avoid race condition. We cannot remove - // Path from a different thread because we are now going to create - // Path as a new file. If we do that in a different thread, the new - // thread can remove the new file. - SmallString<128> TempPath; - if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) - return; - if (sys::fs::rename(Path, TempPath)) { - sys::fs::remove(TempPath); - return; - } - - // Remove TempPath in background. - std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); -} - // Open a result file. template void Writer::openFile() { unlinkAsync(Config->OutputFile);