1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
//===-- SubprocessMemory.cpp ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "SubprocessMemory.h"
#include "Error.h"
#include "llvm/Support/Error.h"
#include <cerrno>
#ifdef __linux__
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#endif
namespace llvm {
namespace exegesis {
#if defined(__linux__) && !defined(__ANDROID__)
Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID) {
// Add the PID to the shared memory name so that if we're running multiple
// processes at the same time, they won't interfere with each other.
// This comes up particularly often when running the exegesis tests with
// llvm-lit
std::string AuxiliaryMemoryName = "/auxmem" + std::to_string(ProcessID);
int AuxiliaryMemoryFD = shm_open(AuxiliaryMemoryName.c_str(),
O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (AuxiliaryMemoryFD == -1)
return make_error<Failure>(
"Failed to create shared memory object for auxiliary memory: " +
Twine(strerror(errno)));
if (ftruncate(AuxiliaryMemoryFD, AuxiliaryMemorySize) != 0) {
return make_error<Failure>("Truncating the auxiliary memory failed: " +
Twine(strerror(errno)));
}
SharedMemoryNames.push_back(AuxiliaryMemoryName);
return Error::success();
}
Error SubprocessMemory::addMemoryDefinition(
std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
pid_t ProcessPID) {
SharedMemoryNames.reserve(MemoryDefinitions.size());
for (auto &[Name, MemVal] : MemoryDefinitions) {
std::string SharedMemoryName = "/" + std::to_string(ProcessPID) + "memdef" +
std::to_string(MemVal.Index);
SharedMemoryNames.push_back(SharedMemoryName);
int SharedMemoryFD =
shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (ftruncate(SharedMemoryFD, MemVal.SizeBytes) != 0) {
return make_error<Failure>("Truncating a memory definiton failed: " +
Twine(strerror(errno)));
}
char *SharedMemoryMapping =
(char *)mmap(NULL, MemVal.SizeBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
SharedMemoryFD, 0);
// fill the buffer with the specified value
size_t CurrentByte = 0;
const size_t ValueWidthBytes = MemVal.Value.getBitWidth() / 8;
while (CurrentByte < MemVal.SizeBytes - ValueWidthBytes) {
memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(),
ValueWidthBytes);
CurrentByte += ValueWidthBytes;
}
// fill the last section
memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(),
MemVal.SizeBytes - CurrentByte);
if (munmap(SharedMemoryMapping, MemVal.SizeBytes) != 0) {
return make_error<Failure>(
"Unmapping a memory definition in the parent failed: " +
Twine(strerror(errno)));
}
}
return Error::success();
}
Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
pid_t ParentPID, int CounterFileDescriptor) {
std::string AuxiliaryMemoryName = "/auxmem" + std::to_string(ParentPID);
int AuxiliaryMemoryFileDescriptor =
shm_open(AuxiliaryMemoryName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
if (AuxiliaryMemoryFileDescriptor == -1)
return make_error<Failure>(
"Getting file descriptor for auxiliary memory failed");
// set up memory value file descriptors
int *AuxiliaryMemoryMapping =
(int *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED,
AuxiliaryMemoryFileDescriptor, 0);
if ((intptr_t)AuxiliaryMemoryMapping == -1)
return make_error<Failure>("Mapping auxiliary memory failed");
AuxiliaryMemoryMapping[0] = CounterFileDescriptor;
for (auto &[Name, MemVal] : MemoryDefinitions) {
std::string MemoryValueName = "/" + std::to_string(ParentPID) + "memdef" +
std::to_string(MemVal.Index);
AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] =
shm_open(MemoryValueName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
if (AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] == -1)
return make_error<Failure>("Mapping shared memory failed");
}
if (munmap(AuxiliaryMemoryMapping, 4096) == -1)
return make_error<Failure>("Unmapping auxiliary memory failed");
return AuxiliaryMemoryFileDescriptor;
}
SubprocessMemory::~SubprocessMemory() {
for (std::string SharedMemoryName : SharedMemoryNames) {
if (shm_unlink(SharedMemoryName.c_str()) != 0) {
errs() << "Failed to unlink shared memory section: " << strerror(errno)
<< "\n";
}
}
}
#else
Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID) {
return make_error<Failure>(
"initializeSubprocessMemory is only supported on Linux");
}
Error SubprocessMemory::addMemoryDefinition(
std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
pid_t ProcessPID) {
return make_error<Failure>("addMemoryDefinitions is only supported on Linux");
}
Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
pid_t ParentPID, int CounterFileDescriptor) {
return make_error<Failure>(
"setupAuxiliaryMemoryInSubprocess is only supported on Linux");
}
SubprocessMemory::~SubprocessMemory() {}
#endif // defined(__linux__) && !defined(__ANDROID__)
} // namespace exegesis
} // namespace llvm
|