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