Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/Common/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 "lld/Common/Filesystem.h"
14
#include "lld/Common/Threads.h"
15
#include "llvm/Config/llvm-config.h"
16
#include "llvm/Support/FileOutputBuffer.h"
17
#include "llvm/Support/FileSystem.h"
18
#if LLVM_ON_UNIX
19
#include <unistd.h>
20
#endif
21
#include <thread>
22
23
using namespace llvm;
24
using namespace lld;
25
26
// Removes a given file asynchronously. This is a performance hack,
27
// so remove this when operating systems are improved.
28
//
29
// On Linux (and probably on other Unix-like systems), unlink(2) is a
30
// noticeably slow system call. As of 2016, unlink takes 250
31
// milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
32
//
33
// To create a new result file, we first remove existing file. So, if
34
// you repeatedly link a 1 GB program in a regular compile-link-debug
35
// cycle, every cycle wastes 250 milliseconds only to remove a file.
36
// Since LLD can link a 1 GB binary in about 5 seconds, that waste
37
// actually counts.
38
//
39
// This function spawns a background thread to remove the file.
40
// The calling thread returns almost immediately.
41
2.57k
void lld::unlinkAsync(StringRef path) {
42
2.57k
// Removing a file is async on windows.
43
#if defined(_WIN32)
44
  sys::fs::remove(path);
45
#else
46
2.57k
  if (!threadsEnabled || 
!sys::fs::exists(path)2.57k
||
47
2.57k
      
!sys::fs::is_regular_file(path)693
)
48
2.03k
    return;
49
543
50
543
  // We cannot just remove path from a different thread because we are now going
51
543
  // to create path as a new file.
52
543
  // Instead we open the file and unlink it on this thread. The unlink is fast
53
543
  // since the open fd guarantees that it is not removing the last reference.
54
543
  int fd;
55
543
  std::error_code ec = sys::fs::openFileForRead(path, fd);
56
543
  sys::fs::remove(path);
57
543
58
543
  if (ec)
59
0
    return;
60
543
61
543
  // close and therefore remove TempPath in background.
62
543
  std::mutex m;
63
543
  std::condition_variable cv;
64
543
  bool started = false;
65
543
  std::thread([&, fd] {
66
543
    {
67
543
      std::lock_guard<std::mutex> l(m);
68
543
      started = true;
69
543
      cv.notify_all();
70
543
    }
71
543
    ::close(fd);
72
543
  }).detach();
73
543
74
543
  // GLIBC 2.26 and earlier have race condition that crashes an entire process
75
543
  // if the main thread calls exit(2) while other thread is starting up.
76
543
  std::unique_lock<std::mutex> l(m);
77
543
  cv.wait(l, [&] { return started; });
78
543
#endif
79
543
}
80
81
// Simulate file creation to see if Path is writable.
82
//
83
// Determining whether a file is writable or not is amazingly hard,
84
// and after all the only reliable way of doing that is to actually
85
// create a file. But we don't want to do that in this function
86
// because LLD shouldn't update any file if it will end in a failure.
87
// We also don't want to reimplement heuristics to determine if a
88
// file is writable. So we'll let FileOutputBuffer do the work.
89
//
90
// FileOutputBuffer doesn't touch a desitnation file until commit()
91
// is called. We use that class without calling commit() to predict
92
// if the given file is writable.
93
6.32k
std::error_code lld::tryCreateFile(StringRef path) {
94
6.32k
  if (path.empty())
95
2.83k
    return std::error_code();
96
3.49k
  if (path == "-")
97
11
    return std::error_code();
98
3.48k
  return errorToErrorCode(FileOutputBuffer::create(path, 1).takeError());
99
3.48k
}