Coverage Report

Created: 2019-03-11 12:38

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/ELF/Filesystem.cpp
Line
Count
Source (jump to first uncovered line)
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
1.56k
void elf::unlinkAsync(StringRef Path) {
45
1.56k
// Removing a file is async on windows.
46
#if defined(_WIN32)
47
  sys::fs::remove(Path);
48
#else
49
1.56k
  if (!ThreadsEnabled || 
!sys::fs::exists(Path)1.56k
||
50
1.56k
      
!sys::fs::is_regular_file(Path)417
)
51
1.24k
    return;
52
321
53
321
  // We cannot just remove path from a different thread because we are now going
54
321
  // to create path as a new file.
55
321
  // Instead we open the file and unlink it on this thread. The unlink is fast
56
321
  // since the open fd guarantees that it is not removing the last reference.
57
321
  int FD;
58
321
  std::error_code EC = sys::fs::openFileForRead(Path, FD);
59
321
  sys::fs::remove(Path);
60
321
61
321
  if (EC)
62
0
    return;
63
321
64
321
  // close and therefore remove TempPath in background.
65
321
  std::mutex M;
66
321
  std::condition_variable CV;
67
321
  bool Started = false;
68
321
  std::thread([&, FD] {
69
321
    {
70
321
      std::lock_guard<std::mutex> L(M);
71
321
      Started = true;
72
321
      CV.notify_all();
73
321
    }
74
321
    ::close(FD);
75
321
  }).detach();
76
321
77
321
  // GLIBC 2.26 and earlier have race condition that crashes an entire process
78
321
  // if the main thread calls exit(2) while other thread is starting up.
79
321
  std::unique_lock<std::mutex> L(M);
80
321
  CV.wait(L, [&] { return Started; });
81
321
#endif
82
321
}
83
84
// Simulate file creation to see if Path is writable.
85
//
86
// Determining whether a file is writable or not is amazingly hard,
87
// and after all the only reliable way of doing that is to actually
88
// create a file. But we don't want to do that in this function
89
// because LLD shouldn't update any file if it will end in a failure.
90
// We also don't want to reimplement heuristics to determine if a
91
// file is writable. So we'll let FileOutputBuffer do the work.
92
//
93
// FileOutputBuffer doesn't touch a desitnation file until commit()
94
// is called. We use that class without calling commit() to predict
95
// if the given file is writable.
96
3.44k
std::error_code elf::tryCreateFile(StringRef Path) {
97
3.44k
  if (Path.empty())
98
1.71k
    return std::error_code();
99
1.73k
  if (Path == "-")
100
7
    return std::error_code();
101
1.73k
  return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError());
102
1.73k
}