1 //===---------- ExecutorSharedMemoryMapperService.cpp -----------*- C++ -*-===// 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 #include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h" 10 11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 12 #include "llvm/Support/Process.h" 13 #include "llvm/Support/WindowsError.h" 14 15 #include <sstream> 16 17 #if defined(LLVM_ON_UNIX) 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <sys/mman.h> 21 #include <unistd.h> 22 #endif 23 24 #if defined(_WIN32) 25 static DWORD getWindowsProtectionFlags(unsigned Flags) { 26 switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { 27 case llvm::sys::Memory::MF_READ: 28 return PAGE_READONLY; 29 case llvm::sys::Memory::MF_WRITE: 30 // Note: PAGE_WRITE is not supported by VirtualProtect 31 return PAGE_READWRITE; 32 case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE: 33 return PAGE_READWRITE; 34 case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_EXEC: 35 return PAGE_EXECUTE_READ; 36 case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE | 37 llvm::sys::Memory::MF_EXEC: 38 return PAGE_EXECUTE_READWRITE; 39 case llvm::sys::Memory::MF_EXEC: 40 return PAGE_EXECUTE; 41 default: 42 llvm_unreachable("Illegal memory protection flag specified!"); 43 } 44 // Provide a default return value as required by some compilers. 45 return PAGE_NOACCESS; 46 } 47 #endif 48 49 namespace llvm { 50 namespace orc { 51 namespace rt_bootstrap { 52 53 Expected<std::pair<ExecutorAddr, std::string>> 54 ExecutorSharedMemoryMapperService::reserve(uint64_t Size) { 55 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32) 56 57 #if defined(LLVM_ON_UNIX) 58 59 std::string SharedMemoryName; 60 { 61 std::stringstream SharedMemoryNameStream; 62 SharedMemoryNameStream << "/jitlink_" << sys::Process::getProcessId() << '_' 63 << (++SharedMemoryCount); 64 SharedMemoryName = SharedMemoryNameStream.str(); 65 } 66 67 int SharedMemoryFile = 68 shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0700); 69 if (SharedMemoryFile < 0) 70 return errorCodeToError(std::error_code(errno, std::generic_category())); 71 72 // by default size is 0 73 if (ftruncate(SharedMemoryFile, Size) < 0) 74 return errorCodeToError(std::error_code(errno, std::generic_category())); 75 76 void *Addr = mmap(nullptr, Size, PROT_NONE, MAP_SHARED, SharedMemoryFile, 0); 77 if (Addr == MAP_FAILED) 78 return errorCodeToError(std::error_code(errno, std::generic_category())); 79 80 close(SharedMemoryFile); 81 82 #elif defined(_WIN32) 83 84 std::string SharedMemoryName; 85 { 86 std::stringstream SharedMemoryNameStream; 87 SharedMemoryNameStream << "jitlink_" << sys::Process::getProcessId() << '_' 88 << (++SharedMemoryCount); 89 SharedMemoryName = SharedMemoryNameStream.str(); 90 } 91 92 std::wstring WideSharedMemoryName(SharedMemoryName.begin(), 93 SharedMemoryName.end()); 94 HANDLE SharedMemoryFile = CreateFileMappingW( 95 INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, Size >> 32, 96 Size & 0xffffffff, WideSharedMemoryName.c_str()); 97 if (!SharedMemoryFile) 98 return errorCodeToError(mapWindowsError(GetLastError())); 99 100 void *Addr = MapViewOfFile(SharedMemoryFile, 101 FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0); 102 if (!Addr) { 103 CloseHandle(SharedMemoryFile); 104 return errorCodeToError(mapWindowsError(GetLastError())); 105 } 106 107 #endif 108 109 { 110 std::lock_guard<std::mutex> Lock(Mutex); 111 Reservations[Addr].Size = Size; 112 #if defined(_WIN32) 113 Reservations[Addr].SharedMemoryFile = SharedMemoryFile; 114 #endif 115 } 116 117 return std::make_pair(ExecutorAddr::fromPtr(Addr), 118 std::move(SharedMemoryName)); 119 #else 120 return make_error<StringError>( 121 "SharedMemoryMapper is not supported on this platform yet", 122 inconvertibleErrorCode()); 123 #endif 124 } 125 126 Expected<ExecutorAddr> ExecutorSharedMemoryMapperService::initialize( 127 ExecutorAddr Reservation, tpctypes::SharedMemoryFinalizeRequest &FR) { 128 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32) 129 130 ExecutorAddr MinAddr(~0ULL); 131 132 // Contents are already in place 133 for (auto &Segment : FR.Segments) { 134 if (Segment.Addr < MinAddr) 135 MinAddr = Segment.Addr; 136 137 #if defined(LLVM_ON_UNIX) 138 139 int NativeProt = 0; 140 if ((Segment.AG.getMemProt() & MemProt::Read) == MemProt::Read) 141 NativeProt |= PROT_READ; 142 if ((Segment.AG.getMemProt() & MemProt::Write) == MemProt::Write) 143 NativeProt |= PROT_WRITE; 144 if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec) 145 NativeProt |= PROT_EXEC; 146 147 if (mprotect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt)) 148 return errorCodeToError(std::error_code(errno, std::generic_category())); 149 150 #elif defined(_WIN32) 151 152 DWORD NativeProt = 153 getWindowsProtectionFlags(fromWireProtectionFlags(Segment.Prot)); 154 155 if (!VirtualProtect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt, 156 &NativeProt)) 157 return errorCodeToError(mapWindowsError(GetLastError())); 158 159 #endif 160 161 if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec) 162 sys::Memory::InvalidateInstructionCache(Segment.Addr.toPtr<void *>(), 163 Segment.Size); 164 } 165 166 // Run finalization actions and get deinitlization action list. 167 auto DeinitializeActions = shared::runFinalizeActions(FR.Actions); 168 if (!DeinitializeActions) { 169 return DeinitializeActions.takeError(); 170 } 171 172 { 173 std::lock_guard<std::mutex> Lock(Mutex); 174 Allocations[MinAddr].DeinitializationActions = 175 std::move(*DeinitializeActions); 176 Reservations[Reservation.toPtr<void *>()].Allocations.push_back(MinAddr); 177 } 178 179 return MinAddr; 180 181 #else 182 return make_error<StringError>( 183 "SharedMemoryMapper is not supported on this platform yet", 184 inconvertibleErrorCode()); 185 #endif 186 } 187 188 Error ExecutorSharedMemoryMapperService::deinitialize( 189 const std::vector<ExecutorAddr> &Bases) { 190 Error AllErr = Error::success(); 191 192 { 193 std::lock_guard<std::mutex> Lock(Mutex); 194 195 for (auto Base : llvm::reverse(Bases)) { 196 if (Error Err = shared::runDeallocActions( 197 Allocations[Base].DeinitializationActions)) { 198 AllErr = joinErrors(std::move(AllErr), std::move(Err)); 199 } 200 201 // Remove the allocation from the allocation list of its reservation 202 for (auto &Reservation : Reservations) { 203 auto AllocationIt = 204 std::find(Reservation.second.Allocations.begin(), 205 Reservation.second.Allocations.end(), Base); 206 if (AllocationIt != Reservation.second.Allocations.end()) { 207 Reservation.second.Allocations.erase(AllocationIt); 208 break; 209 } 210 } 211 212 Allocations.erase(Base); 213 } 214 } 215 216 return AllErr; 217 } 218 219 Error ExecutorSharedMemoryMapperService::release( 220 const std::vector<ExecutorAddr> &Bases) { 221 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32) 222 Error Err = Error::success(); 223 224 for (auto Base : Bases) { 225 std::vector<ExecutorAddr> AllocAddrs; 226 size_t Size; 227 228 #if defined(_WIN32) 229 HANDLE SharedMemoryFile; 230 #endif 231 232 { 233 std::lock_guard<std::mutex> Lock(Mutex); 234 auto &R = Reservations[Base.toPtr<void *>()]; 235 Size = R.Size; 236 237 #if defined(_WIN32) 238 SharedMemoryFile = R.SharedMemoryFile; 239 #endif 240 241 AllocAddrs.swap(R.Allocations); 242 } 243 244 // deinitialize sub allocations 245 if (Error E = deinitialize(AllocAddrs)) 246 Err = joinErrors(std::move(Err), std::move(E)); 247 248 #if defined(LLVM_ON_UNIX) 249 250 if (munmap(Base.toPtr<void *>(), Size) != 0) 251 Err = joinErrors(std::move(Err), errorCodeToError(std::error_code( 252 errno, std::generic_category()))); 253 254 #elif defined(_WIN32) 255 (void)Size; 256 257 if (!UnmapViewOfFile(Base.toPtr<void *>())) 258 Err = joinErrors(std::move(Err), 259 errorCodeToError(mapWindowsError(GetLastError()))); 260 261 CloseHandle(SharedMemoryFile); 262 263 #endif 264 265 std::lock_guard<std::mutex> Lock(Mutex); 266 Reservations.erase(Base.toPtr<void *>()); 267 } 268 269 return Err; 270 #else 271 return make_error<StringError>( 272 "SharedMemoryMapper is not supported on this platform yet", 273 inconvertibleErrorCode()); 274 #endif 275 } 276 277 Error ExecutorSharedMemoryMapperService::shutdown() { 278 if (Reservations.empty()) 279 return Error::success(); 280 281 std::vector<ExecutorAddr> ReservationAddrs; 282 ReservationAddrs.reserve(Reservations.size()); 283 for (const auto &R : Reservations) 284 ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst())); 285 286 return release(std::move(ReservationAddrs)); 287 } 288 289 void ExecutorSharedMemoryMapperService::addBootstrapSymbols( 290 StringMap<ExecutorAddr> &M) { 291 M[rt::ExecutorSharedMemoryMapperServiceInstanceName] = 292 ExecutorAddr::fromPtr(this); 293 M[rt::ExecutorSharedMemoryMapperServiceReserveWrapperName] = 294 ExecutorAddr::fromPtr(&reserveWrapper); 295 M[rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName] = 296 ExecutorAddr::fromPtr(&initializeWrapper); 297 M[rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName] = 298 ExecutorAddr::fromPtr(&deinitializeWrapper); 299 M[rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName] = 300 ExecutorAddr::fromPtr(&releaseWrapper); 301 } 302 303 llvm::orc::shared::CWrapperFunctionResult 304 ExecutorSharedMemoryMapperService::reserveWrapper(const char *ArgData, 305 size_t ArgSize) { 306 return shared::WrapperFunction< 307 rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>:: 308 handle(ArgData, ArgSize, 309 shared::makeMethodWrapperHandler( 310 &ExecutorSharedMemoryMapperService::reserve)) 311 .release(); 312 } 313 314 llvm::orc::shared::CWrapperFunctionResult 315 ExecutorSharedMemoryMapperService::initializeWrapper(const char *ArgData, 316 size_t ArgSize) { 317 return shared::WrapperFunction< 318 rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>:: 319 handle(ArgData, ArgSize, 320 shared::makeMethodWrapperHandler( 321 &ExecutorSharedMemoryMapperService::initialize)) 322 .release(); 323 } 324 325 llvm::orc::shared::CWrapperFunctionResult 326 ExecutorSharedMemoryMapperService::deinitializeWrapper(const char *ArgData, 327 size_t ArgSize) { 328 return shared::WrapperFunction< 329 rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>:: 330 handle(ArgData, ArgSize, 331 shared::makeMethodWrapperHandler( 332 &ExecutorSharedMemoryMapperService::deinitialize)) 333 .release(); 334 } 335 336 llvm::orc::shared::CWrapperFunctionResult 337 ExecutorSharedMemoryMapperService::releaseWrapper(const char *ArgData, 338 size_t ArgSize) { 339 return shared::WrapperFunction< 340 rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>:: 341 handle(ArgData, ArgSize, 342 shared::makeMethodWrapperHandler( 343 &ExecutorSharedMemoryMapperService::release)) 344 .release(); 345 } 346 347 } // namespace rt_bootstrap 348 } // end namespace orc 349 } // end namespace llvm 350