/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/LTO/Caching.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-Caching.cpp - LLVM Link Time Optimizer Cache Handling ---------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
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 implements the Caching for ThinLTO. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "llvm/LTO/Caching.h" |
15 | | #include "llvm/ADT/StringExtras.h" |
16 | | #include "llvm/Support/Errc.h" |
17 | | #include "llvm/Support/FileSystem.h" |
18 | | #include "llvm/Support/MemoryBuffer.h" |
19 | | #include "llvm/Support/Path.h" |
20 | | #include "llvm/Support/raw_ostream.h" |
21 | | |
22 | | using namespace llvm; |
23 | | using namespace llvm::lto; |
24 | | |
25 | | Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath, |
26 | 32 | AddBufferFn AddBuffer) { |
27 | 32 | if (std::error_code EC = sys::fs::create_directories(CacheDirectoryPath)) |
28 | 0 | return errorCodeToError(EC); |
29 | 32 | |
30 | 32 | return [=](unsigned Task, StringRef Key) -> AddStreamFn 32 { |
31 | 46 | // This choice of file name allows the cache to be pruned (see pruneCache() |
32 | 46 | // in include/llvm/Support/CachePruning.h). |
33 | 46 | SmallString<64> EntryPath; |
34 | 46 | sys::path::append(EntryPath, CacheDirectoryPath, "llvmcache-" + Key); |
35 | 46 | // First, see if we have a cache hit. |
36 | 46 | ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = |
37 | 46 | MemoryBuffer::getFile(EntryPath); |
38 | 46 | if (MBOrErr46 ) { |
39 | 4 | AddBuffer(Task, std::move(*MBOrErr), EntryPath); |
40 | 4 | return AddStreamFn(); |
41 | 4 | } |
42 | 42 | |
43 | 42 | if (42 MBOrErr.getError() != errc::no_such_file_or_directory42 ) |
44 | 0 | report_fatal_error(Twine("Failed to open cache file ") + EntryPath + |
45 | 0 | ": " + MBOrErr.getError().message() + "\n"); |
46 | 42 | |
47 | 42 | // This native object stream is responsible for commiting the resulting |
48 | 42 | // file to the cache and calling AddBuffer to add it to the link. |
49 | 42 | struct CacheStream : NativeObjectStream { |
50 | 42 | AddBufferFn AddBuffer; |
51 | 42 | std::string TempFilename; |
52 | 42 | std::string EntryPath; |
53 | 42 | unsigned Task; |
54 | 42 | |
55 | 42 | CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddBufferFn AddBuffer, |
56 | 42 | std::string TempFilename, std::string EntryPath, |
57 | 42 | unsigned Task) |
58 | 42 | : NativeObjectStream(std::move(OS)), AddBuffer(std::move(AddBuffer)), |
59 | 42 | TempFilename(std::move(TempFilename)), |
60 | 42 | EntryPath(std::move(EntryPath)), Task(Task) {} |
61 | 42 | |
62 | 42 | ~CacheStream() { |
63 | 42 | // Make sure the file is closed before committing it. |
64 | 42 | OS.reset(); |
65 | 42 | |
66 | 42 | // Open the file first to avoid racing with a cache pruner. |
67 | 42 | ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = |
68 | 42 | MemoryBuffer::getFile(TempFilename); |
69 | 42 | |
70 | 42 | // This is atomic on POSIX systems. |
71 | 42 | if (auto EC = sys::fs::rename(TempFilename, EntryPath)) |
72 | 0 | report_fatal_error(Twine("Failed to rename temporary file ") + |
73 | 0 | TempFilename + ": " + EC.message() + "\n"); |
74 | 42 | |
75 | 42 | if (42 !MBOrErr42 ) |
76 | 0 | report_fatal_error(Twine("Failed to open cache file ") + EntryPath + |
77 | 0 | ": " + MBOrErr.getError().message() + "\n"); |
78 | 42 | AddBuffer(Task, std::move(*MBOrErr), EntryPath); |
79 | 42 | } |
80 | 42 | }; |
81 | 42 | |
82 | 42 | return [=](size_t Task) -> std::unique_ptr<NativeObjectStream> { |
83 | 42 | // Write to a temporary to avoid race condition |
84 | 42 | int TempFD; |
85 | 42 | SmallString<64> TempFilenameModel, TempFilename; |
86 | 42 | sys::path::append(TempFilenameModel, CacheDirectoryPath, "Thin-%%%%%%.tmp.o"); |
87 | 42 | std::error_code EC = |
88 | 42 | sys::fs::createUniqueFile(TempFilenameModel, TempFD, TempFilename, |
89 | 42 | sys::fs::owner_read | sys::fs::owner_write); |
90 | 42 | if (EC42 ) { |
91 | 0 | errs() << "Error: " << EC.message() << "\n"; |
92 | 0 | report_fatal_error("ThinLTO: Can't get a temporary file"); |
93 | 0 | } |
94 | 42 | |
95 | 42 | // This CacheStream will move the temporary file into the cache when done. |
96 | 42 | return llvm::make_unique<CacheStream>( |
97 | 42 | llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true), |
98 | 42 | AddBuffer, TempFilename.str(), EntryPath.str(), Task); |
99 | 42 | }; |
100 | 46 | }; |
101 | 32 | } |