Coverage Report

Created: 2018-01-17 17:22

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/ELF/Filesystem.cpp
Line
Count
Source
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
1.69k
void elf::unlinkAsync(StringRef Path) {
46
1.69k
// Removing a file is async on windows.
47
#if defined(LLVM_ON_WIN32)
48
  sys::fs::remove(Path);
49
#else
50
1.69k
  if (!ThreadsEnabled || 
!sys::fs::exists(Path)1.69k
||
51
1.69k
      
!sys::fs::is_regular_file(Path)320
)
52
1.37k
    return;
53
316
54
316
  // We cannot just remove path from a different thread because we are now going
55
316
  // to create path as a new file.
56
316
  // Instead we open the file and unlink it on this thread. The unlink is fast
57
316
  // since the open fd guarantees that it is not removing the last reference.
58
316
  int FD;
59
316
  std::error_code EC = sys::fs::openFileForRead(Path, FD);
60
316
  sys::fs::remove(Path);
61
316
62
316
  // close and therefore remove TempPath in background.
63
316
  if (!EC)
64
316
    std::thread([=] { ::close(FD); }).detach();
65
316
#endif
66
316
}
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
3.71k
std::error_code elf::tryCreateFile(StringRef Path) {
81
3.71k
  if (Path.empty())
82
1.84k
    return std::error_code();
83
1.86k
  if (Path == "-")
84
5
    return std::error_code();
85
1.86k
  return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError());
86
1.86k
}