Coverage Report

Created: 2018-10-23 15:26

/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
2.19k
void elf::unlinkAsync(StringRef Path) {
46
2.19k
// Removing a file is async on windows.
47
#if defined(_WIN32)
48
  sys::fs::remove(Path);
49
#else
50
2.19k
  if (!ThreadsEnabled || 
!sys::fs::exists(Path)2.18k
||
51
2.19k
      
!sys::fs::is_regular_file(Path)589
)
52
1.73k
    return;
53
456
54
456
  // We cannot just remove path from a different thread because we are now going
55
456
  // to create path as a new file.
56
456
  // Instead we open the file and unlink it on this thread. The unlink is fast
57
456
  // since the open fd guarantees that it is not removing the last reference.
58
456
  int FD;
59
456
  std::error_code EC = sys::fs::openFileForRead(Path, FD);
60
456
  sys::fs::remove(Path);
61
456
62
456
  // close and therefore remove TempPath in background.
63
456
  if (!EC)
64
456
    std::thread([=] { ::close(FD); }).detach();
65
456
#endif
66
456
}
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
4.85k
std::error_code elf::tryCreateFile(StringRef Path) {
81
4.85k
  if (Path.empty())
82
2.41k
    return std::error_code();
83
2.44k
  if (Path == "-")
84
9
    return std::error_code();
85
2.43k
  return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError());
86
2.43k
}