1 //===-- SubprocessMemory.cpp ------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "SubprocessMemory.h"
11 #include "llvm/ADT/ScopeExit.h"
12 #include "llvm/Support/Error.h"
13 #include "llvm/Support/FormatVariadic.h"
19 #include <sys/syscall.h>
26 #if defined(__linux__)
28 // The SYS_* macros for system calls are provided by the libc whereas the
29 // __NR_* macros are from the linux headers. This means that sometimes
30 // SYS_* macros might not be available for certain system calls depending
31 // upon the libc. This happens with the gettid syscall and bionic for
32 // example, so we use __NR_gettid when no SYS_gettid is available.
34 #define SYS_gettid __NR_gettid
37 long SubprocessMemory::getCurrentTID() {
38 // We're using the raw syscall here rather than the gettid() function provided
39 // by most libcs for compatibility as gettid() was only added to glibc in
41 return syscall(SYS_gettid
);
44 #if !defined(__ANDROID__)
46 Error
SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID
) {
47 // Add the PID to the shared memory name so that if we're running multiple
48 // processes at the same time, they won't interfere with each other.
49 // This comes up particularly often when running the exegesis tests with
50 // llvm-lit. Additionally add the TID so that downstream consumers
51 // using multiple threads don't run into conflicts.
52 std::string AuxiliaryMemoryName
=
53 formatv("/{0}auxmem{1}", getCurrentTID(), ProcessID
);
54 int AuxiliaryMemoryFD
= shm_open(AuxiliaryMemoryName
.c_str(),
55 O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
56 if (AuxiliaryMemoryFD
== -1)
57 return make_error
<Failure
>(
58 "Failed to create shared memory object for auxiliary memory: " +
59 Twine(strerror(errno
)));
60 auto AuxiliaryMemoryFDClose
=
61 make_scope_exit([AuxiliaryMemoryFD
]() { close(AuxiliaryMemoryFD
); });
62 if (ftruncate(AuxiliaryMemoryFD
, AuxiliaryMemorySize
) != 0) {
63 return make_error
<Failure
>("Truncating the auxiliary memory failed: " +
64 Twine(strerror(errno
)));
66 SharedMemoryNames
.push_back(AuxiliaryMemoryName
);
67 return Error::success();
70 Error
SubprocessMemory::addMemoryDefinition(
71 std::unordered_map
<std::string
, MemoryValue
> MemoryDefinitions
,
73 SharedMemoryNames
.reserve(MemoryDefinitions
.size());
74 for (auto &[Name
, MemVal
] : MemoryDefinitions
) {
75 std::string SharedMemoryName
=
76 formatv("/{0}t{1}memdef{2}", ProcessPID
, getCurrentTID(), MemVal
.Index
);
77 SharedMemoryNames
.push_back(SharedMemoryName
);
79 shm_open(SharedMemoryName
.c_str(), O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
80 if (SharedMemoryFD
== -1)
81 return make_error
<Failure
>(
82 "Failed to create shared memory object for memory definition: " +
83 Twine(strerror(errno
)));
84 auto SharedMemoryFDClose
=
85 make_scope_exit([SharedMemoryFD
]() { close(SharedMemoryFD
); });
86 if (ftruncate(SharedMemoryFD
, MemVal
.SizeBytes
) != 0) {
87 return make_error
<Failure
>("Truncating a memory definiton failed: " +
88 Twine(strerror(errno
)));
91 char *SharedMemoryMapping
=
92 (char *)mmap(NULL
, MemVal
.SizeBytes
, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
94 // fill the buffer with the specified value
95 size_t CurrentByte
= 0;
96 const size_t ValueWidthBytes
= MemVal
.Value
.getBitWidth() / 8;
97 while (CurrentByte
< MemVal
.SizeBytes
- ValueWidthBytes
) {
98 memcpy(SharedMemoryMapping
+ CurrentByte
, MemVal
.Value
.getRawData(),
100 CurrentByte
+= ValueWidthBytes
;
102 // fill the last section
103 memcpy(SharedMemoryMapping
+ CurrentByte
, MemVal
.Value
.getRawData(),
104 MemVal
.SizeBytes
- CurrentByte
);
105 if (munmap(SharedMemoryMapping
, MemVal
.SizeBytes
) != 0) {
106 return make_error
<Failure
>(
107 "Unmapping a memory definition in the parent failed: " +
108 Twine(strerror(errno
)));
111 return Error::success();
114 Expected
<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
115 std::unordered_map
<std::string
, MemoryValue
> MemoryDefinitions
,
116 pid_t ParentPID
, long ParentTID
, int CounterFileDescriptor
) {
117 std::string AuxiliaryMemoryName
=
118 formatv("/{0}auxmem{1}", ParentTID
, ParentPID
);
119 int AuxiliaryMemoryFileDescriptor
=
120 shm_open(AuxiliaryMemoryName
.c_str(), O_RDWR
, S_IRUSR
| S_IWUSR
);
121 if (AuxiliaryMemoryFileDescriptor
== -1)
122 return make_error
<Failure
>(
123 "Getting file descriptor for auxiliary memory failed: " +
124 Twine(strerror(errno
)));
125 // set up memory value file descriptors
126 int *AuxiliaryMemoryMapping
=
127 (int *)mmap(NULL
, 4096, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
128 AuxiliaryMemoryFileDescriptor
, 0);
129 if (reinterpret_cast<intptr_t>(AuxiliaryMemoryMapping
) == -1)
130 return make_error
<Failure
>("Mapping auxiliary memory failed");
131 AuxiliaryMemoryMapping
[0] = CounterFileDescriptor
;
132 for (auto &[Name
, MemVal
] : MemoryDefinitions
) {
133 std::string MemoryValueName
=
134 formatv("/{0}t{1}memdef{2}", ParentPID
, ParentTID
, MemVal
.Index
);
135 AuxiliaryMemoryMapping
[AuxiliaryMemoryOffset
+ MemVal
.Index
] =
136 shm_open(MemoryValueName
.c_str(), O_RDWR
, S_IRUSR
| S_IWUSR
);
137 if (AuxiliaryMemoryMapping
[AuxiliaryMemoryOffset
+ MemVal
.Index
] == -1)
138 return make_error
<Failure
>("Mapping shared memory failed");
140 if (munmap(AuxiliaryMemoryMapping
, 4096) == -1)
141 return make_error
<Failure
>("Unmapping auxiliary memory failed");
142 return AuxiliaryMemoryFileDescriptor
;
145 SubprocessMemory::~SubprocessMemory() {
146 for (const std::string
&SharedMemoryName
: SharedMemoryNames
) {
147 if (shm_unlink(SharedMemoryName
.c_str()) != 0) {
148 errs() << "Failed to unlink shared memory section: " << strerror(errno
)
156 Error
SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID
) {
157 return make_error
<Failure
>(
158 "initializeSubprocessMemory is only supported on Linux");
161 Error
SubprocessMemory::addMemoryDefinition(
162 std::unordered_map
<std::string
, MemoryValue
> MemoryDefinitions
,
164 return make_error
<Failure
>("addMemoryDefinitions is only supported on Linux");
167 Expected
<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
168 std::unordered_map
<std::string
, MemoryValue
> MemoryDefinitions
,
169 pid_t ParentPID
, long ParentTID
, int CounterFileDescriptor
) {
170 return make_error
<Failure
>(
171 "setupAuxiliaryMemoryInSubprocess is only supported on Linux");
174 SubprocessMemory::~SubprocessMemory() {}
176 #endif // !defined(__ANDROID__)
177 #endif // defined(__linux__)
179 } // namespace exegesis