Coverage Report

Created: 2019-01-21 03:01

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/ELF/Filesystem.cpp
Line
Count
Source
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 "Filesystem.h"
14
#include "Config.h"
15
#include "lld/Common/Threads.h"
16
#include "llvm/Config/llvm-config.h"
17
#include "llvm/Support/FileOutputBuffer.h"
18
#include "llvm/Support/FileSystem.h"
19
#if LLVM_ON_UNIX
20
#include <unistd.h>
21
#endif
22
#include <thread>
23
24
using namespace llvm;
25
26
using namespace lld;
27
using namespace lld::elf;
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
2.26k
void elf::unlinkAsync(StringRef Path) {
45
2.26k
// Removing a file is async on windows.
46
#if defined(_WIN32)
47
  sys::fs::remove(Path);
48
#else
49
2.26k
  if (!ThreadsEnabled || 
!sys::fs::exists(Path)2.25k
||
50
2.26k
      
!sys::fs::is_regular_file(Path)606
)
51
1.79k
    return;
52
474
53
474
  // We cannot just remove path from a different thread because we are now going
54
474
  // to create path as a new file.
55
474
  // Instead we open the file and unlink it on this thread. The unlink is fast
56
474
  // since the open fd guarantees that it is not removing the last reference.
57
474
  int FD;
58
474
  std::error_code EC = sys::fs::openFileForRead(Path, FD);
59
474
  sys::fs::remove(Path);
60
474
61
474
  // close and therefore remove TempPath in background.
62
474
  if (!EC)
63
474
    std::thread([=] { ::close(FD); }).detach();
64
474
#endif
65
474
}
66
67
// Simulate file creation to see if Path is writable.
68
//
69
// Determining whether a file is writable or not is amazingly hard,
70
// and after all the only reliable way of doing that is to actually
71
// create a file. But we don't want to do that in this function
72
// because LLD shouldn't update any file if it will end in a failure.
73
// We also don't want to reimplement heuristics to determine if a
74
// file is writable. So we'll let FileOutputBuffer do the work.
75
//
76
// FileOutputBuffer doesn't touch a desitnation file until commit()
77
// is called. We use that class without calling commit() to predict
78
// if the given file is writable.
79
5.00k
std::error_code elf::tryCreateFile(StringRef Path) {
80
5.00k
  if (Path.empty())
81
2.48k
    return std::error_code();
82
2.51k
  if (Path == "-")
83
9
    return std::error_code();
84
2.50k
  return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError());
85
2.50k
}