Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp
35266 views
//===- MemoryMapper.cpp - Cross-process memory mapper ------------*- C++ -*-==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ExecutionEngine/Orc/MemoryMapper.h"910#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"11#include "llvm/Support/WindowsError.h"1213#include <algorithm>1415#if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)16#include <fcntl.h>17#include <sys/mman.h>18#if defined(__MVS__)19#include "llvm/Support/BLAKE3.h"20#include <sys/shm.h>21#endif22#include <unistd.h>23#elif defined(_WIN32)24#include <windows.h>25#endif2627namespace llvm {28namespace orc {2930MemoryMapper::~MemoryMapper() {}3132InProcessMemoryMapper::InProcessMemoryMapper(size_t PageSize)33: PageSize(PageSize) {}3435Expected<std::unique_ptr<InProcessMemoryMapper>>36InProcessMemoryMapper::Create() {37auto PageSize = sys::Process::getPageSize();38if (!PageSize)39return PageSize.takeError();40return std::make_unique<InProcessMemoryMapper>(*PageSize);41}4243void InProcessMemoryMapper::reserve(size_t NumBytes,44OnReservedFunction OnReserved) {45std::error_code EC;46auto MB = sys::Memory::allocateMappedMemory(47NumBytes, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);4849if (EC)50return OnReserved(errorCodeToError(EC));5152{53std::lock_guard<std::mutex> Lock(Mutex);54Reservations[MB.base()].Size = MB.allocatedSize();55}5657OnReserved(58ExecutorAddrRange(ExecutorAddr::fromPtr(MB.base()), MB.allocatedSize()));59}6061char *InProcessMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) {62return Addr.toPtr<char *>();63}6465void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,66OnInitializedFunction OnInitialized) {67ExecutorAddr MinAddr(~0ULL);68ExecutorAddr MaxAddr(0);6970// FIXME: Release finalize lifetime segments.71for (auto &Segment : AI.Segments) {72auto Base = AI.MappingBase + Segment.Offset;73auto Size = Segment.ContentSize + Segment.ZeroFillSize;7475if (Base < MinAddr)76MinAddr = Base;7778if (Base + Size > MaxAddr)79MaxAddr = Base + Size;8081std::memset((Base + Segment.ContentSize).toPtr<void *>(), 0,82Segment.ZeroFillSize);8384if (auto EC = sys::Memory::protectMappedMemory(85{Base.toPtr<void *>(), Size},86toSysMemoryProtectionFlags(Segment.AG.getMemProt()))) {87return OnInitialized(errorCodeToError(EC));88}89if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)90sys::Memory::InvalidateInstructionCache(Base.toPtr<void *>(), Size);91}9293auto DeinitializeActions = shared::runFinalizeActions(AI.Actions);94if (!DeinitializeActions)95return OnInitialized(DeinitializeActions.takeError());9697{98std::lock_guard<std::mutex> Lock(Mutex);99100// This is the maximum range whose permission have been possibly modified101Allocations[MinAddr].Size = MaxAddr - MinAddr;102Allocations[MinAddr].DeinitializationActions =103std::move(*DeinitializeActions);104Reservations[AI.MappingBase.toPtr<void *>()].Allocations.push_back(MinAddr);105}106107OnInitialized(MinAddr);108}109110void InProcessMemoryMapper::deinitialize(111ArrayRef<ExecutorAddr> Bases,112MemoryMapper::OnDeinitializedFunction OnDeinitialized) {113Error AllErr = Error::success();114115{116std::lock_guard<std::mutex> Lock(Mutex);117118for (auto Base : llvm::reverse(Bases)) {119120if (Error Err = shared::runDeallocActions(121Allocations[Base].DeinitializationActions)) {122AllErr = joinErrors(std::move(AllErr), std::move(Err));123}124125// Reset protections to read/write so the area can be reused126if (auto EC = sys::Memory::protectMappedMemory(127{Base.toPtr<void *>(), Allocations[Base].Size},128sys::Memory::ProtectionFlags::MF_READ |129sys::Memory::ProtectionFlags::MF_WRITE)) {130AllErr = joinErrors(std::move(AllErr), errorCodeToError(EC));131}132133Allocations.erase(Base);134}135}136137OnDeinitialized(std::move(AllErr));138}139140void InProcessMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,141OnReleasedFunction OnReleased) {142Error Err = Error::success();143144for (auto Base : Bases) {145std::vector<ExecutorAddr> AllocAddrs;146size_t Size;147{148std::lock_guard<std::mutex> Lock(Mutex);149auto &R = Reservations[Base.toPtr<void *>()];150Size = R.Size;151AllocAddrs.swap(R.Allocations);152}153154// deinitialize sub allocations155std::promise<MSVCPError> P;156auto F = P.get_future();157deinitialize(AllocAddrs, [&](Error Err) { P.set_value(std::move(Err)); });158if (Error E = F.get()) {159Err = joinErrors(std::move(Err), std::move(E));160}161162// free the memory163auto MB = sys::MemoryBlock(Base.toPtr<void *>(), Size);164165auto EC = sys::Memory::releaseMappedMemory(MB);166if (EC) {167Err = joinErrors(std::move(Err), errorCodeToError(EC));168}169170std::lock_guard<std::mutex> Lock(Mutex);171Reservations.erase(Base.toPtr<void *>());172}173174OnReleased(std::move(Err));175}176177InProcessMemoryMapper::~InProcessMemoryMapper() {178std::vector<ExecutorAddr> ReservationAddrs;179{180std::lock_guard<std::mutex> Lock(Mutex);181182ReservationAddrs.reserve(Reservations.size());183for (const auto &R : Reservations) {184ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));185}186}187188std::promise<MSVCPError> P;189auto F = P.get_future();190release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); });191cantFail(F.get());192}193194// SharedMemoryMapper195196SharedMemoryMapper::SharedMemoryMapper(ExecutorProcessControl &EPC,197SymbolAddrs SAs, size_t PageSize)198: EPC(EPC), SAs(SAs), PageSize(PageSize) {199#if (!defined(LLVM_ON_UNIX) || defined(__ANDROID__)) && !defined(_WIN32)200llvm_unreachable("SharedMemoryMapper is not supported on this platform yet");201#endif202}203204Expected<std::unique_ptr<SharedMemoryMapper>>205SharedMemoryMapper::Create(ExecutorProcessControl &EPC, SymbolAddrs SAs) {206#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)207auto PageSize = sys::Process::getPageSize();208if (!PageSize)209return PageSize.takeError();210211return std::make_unique<SharedMemoryMapper>(EPC, SAs, *PageSize);212#else213return make_error<StringError>(214"SharedMemoryMapper is not supported on this platform yet",215inconvertibleErrorCode());216#endif217}218219void SharedMemoryMapper::reserve(size_t NumBytes,220OnReservedFunction OnReserved) {221#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)222223EPC.callSPSWrapperAsync<224rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>(225SAs.Reserve,226[this, NumBytes, OnReserved = std::move(OnReserved)](227Error SerializationErr,228Expected<std::pair<ExecutorAddr, std::string>> Result) mutable {229if (SerializationErr) {230cantFail(Result.takeError());231return OnReserved(std::move(SerializationErr));232}233234if (!Result)235return OnReserved(Result.takeError());236237ExecutorAddr RemoteAddr;238std::string SharedMemoryName;239std::tie(RemoteAddr, SharedMemoryName) = std::move(*Result);240241void *LocalAddr = nullptr;242243#if defined(LLVM_ON_UNIX)244245#if defined(__MVS__)246ArrayRef<uint8_t> Data(247reinterpret_cast<const uint8_t *>(SharedMemoryName.c_str()),248SharedMemoryName.size());249auto HashedName = BLAKE3::hash<sizeof(key_t)>(Data);250key_t Key = *reinterpret_cast<key_t *>(HashedName.data());251int SharedMemoryId =252shmget(Key, NumBytes, IPC_CREAT | __IPC_SHAREAS | 0700);253if (SharedMemoryId < 0) {254return OnReserved(errorCodeToError(255std::error_code(errno, std::generic_category())));256}257LocalAddr = shmat(SharedMemoryId, nullptr, 0);258if (LocalAddr == reinterpret_cast<void *>(-1)) {259return OnReserved(errorCodeToError(260std::error_code(errno, std::generic_category())));261}262#else263int SharedMemoryFile = shm_open(SharedMemoryName.c_str(), O_RDWR, 0700);264if (SharedMemoryFile < 0) {265return OnReserved(errorCodeToError(errnoAsErrorCode()));266}267268// this prevents other processes from accessing it by name269shm_unlink(SharedMemoryName.c_str());270271LocalAddr = mmap(nullptr, NumBytes, PROT_READ | PROT_WRITE, MAP_SHARED,272SharedMemoryFile, 0);273if (LocalAddr == MAP_FAILED) {274return OnReserved(errorCodeToError(errnoAsErrorCode()));275}276277close(SharedMemoryFile);278#endif279280#elif defined(_WIN32)281282std::wstring WideSharedMemoryName(SharedMemoryName.begin(),283SharedMemoryName.end());284HANDLE SharedMemoryFile = OpenFileMappingW(285FILE_MAP_ALL_ACCESS, FALSE, WideSharedMemoryName.c_str());286if (!SharedMemoryFile)287return OnReserved(errorCodeToError(mapWindowsError(GetLastError())));288289LocalAddr =290MapViewOfFile(SharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);291if (!LocalAddr) {292CloseHandle(SharedMemoryFile);293return OnReserved(errorCodeToError(mapWindowsError(GetLastError())));294}295296CloseHandle(SharedMemoryFile);297298#endif299{300std::lock_guard<std::mutex> Lock(Mutex);301Reservations.insert({RemoteAddr, {LocalAddr, NumBytes}});302}303304OnReserved(ExecutorAddrRange(RemoteAddr, NumBytes));305},306SAs.Instance, static_cast<uint64_t>(NumBytes));307308#else309OnReserved(make_error<StringError>(310"SharedMemoryMapper is not supported on this platform yet",311inconvertibleErrorCode()));312#endif313}314315char *SharedMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) {316auto R = Reservations.upper_bound(Addr);317assert(R != Reservations.begin() && "Attempt to prepare unreserved range");318R--;319320ExecutorAddrDiff Offset = Addr - R->first;321322return static_cast<char *>(R->second.LocalAddr) + Offset;323}324325void SharedMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,326OnInitializedFunction OnInitialized) {327auto Reservation = Reservations.upper_bound(AI.MappingBase);328assert(Reservation != Reservations.begin() && "Attempt to initialize unreserved range");329Reservation--;330331auto AllocationOffset = AI.MappingBase - Reservation->first;332333tpctypes::SharedMemoryFinalizeRequest FR;334335AI.Actions.swap(FR.Actions);336337FR.Segments.reserve(AI.Segments.size());338339for (auto Segment : AI.Segments) {340char *Base = static_cast<char *>(Reservation->second.LocalAddr) +341AllocationOffset + Segment.Offset;342std::memset(Base + Segment.ContentSize, 0, Segment.ZeroFillSize);343344tpctypes::SharedMemorySegFinalizeRequest SegReq;345SegReq.RAG = {Segment.AG.getMemProt(),346Segment.AG.getMemLifetime() == MemLifetime::Finalize};347SegReq.Addr = AI.MappingBase + Segment.Offset;348SegReq.Size = Segment.ContentSize + Segment.ZeroFillSize;349350FR.Segments.push_back(SegReq);351}352353EPC.callSPSWrapperAsync<354rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>(355SAs.Initialize,356[OnInitialized = std::move(OnInitialized)](357Error SerializationErr, Expected<ExecutorAddr> Result) mutable {358if (SerializationErr) {359cantFail(Result.takeError());360return OnInitialized(std::move(SerializationErr));361}362363OnInitialized(std::move(Result));364},365SAs.Instance, Reservation->first, std::move(FR));366}367368void SharedMemoryMapper::deinitialize(369ArrayRef<ExecutorAddr> Allocations,370MemoryMapper::OnDeinitializedFunction OnDeinitialized) {371EPC.callSPSWrapperAsync<372rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>(373SAs.Deinitialize,374[OnDeinitialized = std::move(OnDeinitialized)](Error SerializationErr,375Error Result) mutable {376if (SerializationErr) {377cantFail(std::move(Result));378return OnDeinitialized(std::move(SerializationErr));379}380381OnDeinitialized(std::move(Result));382},383SAs.Instance, Allocations);384}385386void SharedMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,387OnReleasedFunction OnReleased) {388#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)389Error Err = Error::success();390391{392std::lock_guard<std::mutex> Lock(Mutex);393394for (auto Base : Bases) {395396#if defined(LLVM_ON_UNIX)397398#if defined(__MVS__)399if (shmdt(Reservations[Base].LocalAddr) < 0)400Err = joinErrors(std::move(Err), errorCodeToError(errnoAsErrorCode()));401#else402if (munmap(Reservations[Base].LocalAddr, Reservations[Base].Size) != 0)403Err = joinErrors(std::move(Err), errorCodeToError(errnoAsErrorCode()));404#endif405406#elif defined(_WIN32)407408if (!UnmapViewOfFile(Reservations[Base].LocalAddr))409Err = joinErrors(std::move(Err),410errorCodeToError(mapWindowsError(GetLastError())));411412#endif413414Reservations.erase(Base);415}416}417418EPC.callSPSWrapperAsync<419rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>(420SAs.Release,421[OnReleased = std::move(OnReleased),422Err = std::move(Err)](Error SerializationErr, Error Result) mutable {423if (SerializationErr) {424cantFail(std::move(Result));425return OnReleased(426joinErrors(std::move(Err), std::move(SerializationErr)));427}428429return OnReleased(joinErrors(std::move(Err), std::move(Result)));430},431SAs.Instance, Bases);432#else433OnReleased(make_error<StringError>(434"SharedMemoryMapper is not supported on this platform yet",435inconvertibleErrorCode()));436#endif437}438439SharedMemoryMapper::~SharedMemoryMapper() {440std::lock_guard<std::mutex> Lock(Mutex);441for (const auto &R : Reservations) {442443#if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)444445#if defined(__MVS__)446shmdt(R.second.LocalAddr);447#else448munmap(R.second.LocalAddr, R.second.Size);449#endif450451#elif defined(_WIN32)452453UnmapViewOfFile(R.second.LocalAddr);454455#else456457(void)R;458459#endif460}461}462463} // namespace orc464465} // namespace llvm466467468