forked from OSchip/llvm-project
Re-re-apply 5acd471698
, Add a shared-memory based orc::MemoryMapper...
...with more fixes. The original patch was reverted in3e9cc543f2
due to bot failures caused by a missing dependence on librt. That issue was fixed in32d8d23cd0
, but that commit also broke sanitizer bots due to a bug in SimplePackedSerialization: empty ArrayRef<char>s triggered a zero-byte memcpy from a null source. The ArrayRef<char> serialization issue was fixed in67220c2ad7
, and this patch has also been updated with a new custom SharedMemorySegFinalizeRequest message that should avoid serializing empty ArrayRefs in the first place. https://reviews.llvm.org/D128544
This commit is contained in:
parent
1cf6b93df1
commit
1b1f1c7786
|
@ -109,6 +109,47 @@ private:
|
|||
AllocationMap Allocations;
|
||||
};
|
||||
|
||||
class SharedMemoryMapper final : public MemoryMapper {
|
||||
public:
|
||||
struct SymbolAddrs {
|
||||
ExecutorAddr Instance;
|
||||
ExecutorAddr Reserve;
|
||||
ExecutorAddr Initialize;
|
||||
ExecutorAddr Deinitialize;
|
||||
ExecutorAddr Release;
|
||||
};
|
||||
|
||||
SharedMemoryMapper(ExecutorProcessControl &EPC, SymbolAddrs SAs)
|
||||
: EPC(EPC), SAs(SAs) {}
|
||||
|
||||
void reserve(size_t NumBytes, OnReservedFunction OnReserved) override;
|
||||
|
||||
char *prepare(ExecutorAddr Addr, size_t ContentSize) override;
|
||||
|
||||
void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override;
|
||||
|
||||
void deinitialize(ArrayRef<ExecutorAddr> Allocations,
|
||||
OnDeinitializedFunction OnDeInitialized) override;
|
||||
|
||||
void release(ArrayRef<ExecutorAddr> Reservations,
|
||||
OnReleasedFunction OnRelease) override;
|
||||
|
||||
~SharedMemoryMapper() override;
|
||||
|
||||
private:
|
||||
struct Reservation {
|
||||
void *LocalAddr;
|
||||
size_t Size;
|
||||
};
|
||||
|
||||
ExecutorProcessControl &EPC;
|
||||
SymbolAddrs SAs;
|
||||
|
||||
std::mutex Mutex;
|
||||
|
||||
std::map<ExecutorAddr, Reservation> Reservations;
|
||||
};
|
||||
|
||||
} // namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
|
|
|
@ -31,6 +31,12 @@ extern const char *SimpleExecutorMemoryManagerReserveWrapperName;
|
|||
extern const char *SimpleExecutorMemoryManagerFinalizeWrapperName;
|
||||
extern const char *SimpleExecutorMemoryManagerDeallocateWrapperName;
|
||||
|
||||
extern const char *ExecutorSharedMemoryMapperServiceInstanceName;
|
||||
extern const char *ExecutorSharedMemoryMapperServiceReserveWrapperName;
|
||||
extern const char *ExecutorSharedMemoryMapperServiceInitializeWrapperName;
|
||||
extern const char *ExecutorSharedMemoryMapperServiceDeinitializeWrapperName;
|
||||
extern const char *ExecutorSharedMemoryMapperServiceReleaseWrapperName;
|
||||
|
||||
extern const char *MemoryWriteUInt8sWrapperName;
|
||||
extern const char *MemoryWriteUInt16sWrapperName;
|
||||
extern const char *MemoryWriteUInt32sWrapperName;
|
||||
|
@ -58,6 +64,21 @@ using SPSSimpleExecutorMemoryManagerFinalizeSignature =
|
|||
using SPSSimpleExecutorMemoryManagerDeallocateSignature = shared::SPSError(
|
||||
shared::SPSExecutorAddr, shared::SPSSequence<shared::SPSExecutorAddr>);
|
||||
|
||||
// ExecutorSharedMemoryMapperService
|
||||
using SPSExecutorSharedMemoryMapperServiceReserveSignature =
|
||||
shared::SPSExpected<
|
||||
shared::SPSTuple<shared::SPSExecutorAddr, shared::SPSString>>(
|
||||
shared::SPSExecutorAddr, uint64_t);
|
||||
using SPSExecutorSharedMemoryMapperServiceInitializeSignature =
|
||||
shared::SPSExpected<shared::SPSExecutorAddr>(
|
||||
shared::SPSExecutorAddr, shared::SPSExecutorAddr,
|
||||
shared::SPSSharedMemoryFinalizeRequest);
|
||||
using SPSExecutorSharedMemoryMapperServiceDeinitializeSignature =
|
||||
shared::SPSError(shared::SPSExecutorAddr,
|
||||
shared::SPSSequence<shared::SPSExecutorAddr>);
|
||||
using SPSExecutorSharedMemoryMapperServiceReleaseSignature = shared::SPSError(
|
||||
shared::SPSExecutorAddr, shared::SPSSequence<shared::SPSExecutorAddr>);
|
||||
|
||||
using SPSRunAsMainSignature = int64_t(shared::SPSExecutorAddr,
|
||||
shared::SPSSequence<shared::SPSString>);
|
||||
|
||||
|
|
|
@ -82,6 +82,17 @@ struct FinalizeRequest {
|
|||
shared::AllocActions Actions;
|
||||
};
|
||||
|
||||
struct SharedMemorySegFinalizeRequest {
|
||||
WireProtectionFlags Prot;
|
||||
ExecutorAddr Addr;
|
||||
uint64_t Size;
|
||||
};
|
||||
|
||||
struct SharedMemoryFinalizeRequest {
|
||||
std::vector<SharedMemorySegFinalizeRequest> Segments;
|
||||
shared::AllocActions Actions;
|
||||
};
|
||||
|
||||
template <typename T> struct UIntWrite {
|
||||
UIntWrite() = default;
|
||||
UIntWrite(ExecutorAddr Addr, T Value) : Addr(Addr), Value(Value) {}
|
||||
|
@ -131,6 +142,13 @@ using SPSSegFinalizeRequest =
|
|||
using SPSFinalizeRequest = SPSTuple<SPSSequence<SPSSegFinalizeRequest>,
|
||||
SPSSequence<SPSAllocActionCallPair>>;
|
||||
|
||||
using SPSSharedMemorySegFinalizeRequest =
|
||||
SPSTuple<SPSMemoryProtectionFlags, SPSExecutorAddr, uint64_t>;
|
||||
|
||||
using SPSSharedMemoryFinalizeRequest =
|
||||
SPSTuple<SPSSequence<SPSSharedMemorySegFinalizeRequest>,
|
||||
SPSSequence<SPSAllocActionCallPair>>;
|
||||
|
||||
template <typename T>
|
||||
using SPSMemoryAccessUIntWrite = SPSTuple<SPSExecutorAddr, T>;
|
||||
|
||||
|
@ -204,6 +222,48 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSSharedMemorySegFinalizeRequest,
|
||||
tpctypes::SharedMemorySegFinalizeRequest> {
|
||||
using SFRAL = SPSSharedMemorySegFinalizeRequest::AsArgList;
|
||||
|
||||
public:
|
||||
static size_t size(const tpctypes::SharedMemorySegFinalizeRequest &SFR) {
|
||||
return SFRAL::size(SFR.Prot, SFR.Addr, SFR.Size);
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &OB,
|
||||
const tpctypes::SharedMemorySegFinalizeRequest &SFR) {
|
||||
return SFRAL::serialize(OB, SFR.Prot, SFR.Addr, SFR.Size);
|
||||
}
|
||||
|
||||
static bool deserialize(SPSInputBuffer &IB,
|
||||
tpctypes::SharedMemorySegFinalizeRequest &SFR) {
|
||||
return SFRAL::deserialize(IB, SFR.Prot, SFR.Addr, SFR.Size);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSSharedMemoryFinalizeRequest,
|
||||
tpctypes::SharedMemoryFinalizeRequest> {
|
||||
using FRAL = SPSSharedMemoryFinalizeRequest::AsArgList;
|
||||
|
||||
public:
|
||||
static size_t size(const tpctypes::SharedMemoryFinalizeRequest &FR) {
|
||||
return FRAL::size(FR.Segments, FR.Actions);
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &OB,
|
||||
const tpctypes::SharedMemoryFinalizeRequest &FR) {
|
||||
return FRAL::serialize(OB, FR.Segments, FR.Actions);
|
||||
}
|
||||
|
||||
static bool deserialize(SPSInputBuffer &IB,
|
||||
tpctypes::SharedMemoryFinalizeRequest &FR) {
|
||||
return FRAL::deserialize(IB, FR.Segments, FR.Actions);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SPSSerializationTraits<SPSMemoryAccessUIntWrite<T>,
|
||||
tpctypes::UIntWrite<T>> {
|
||||
|
@ -244,7 +304,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace shared
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
//===----------- ExecutorSharedMemoryMapperService.h ------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE
|
||||
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorBootstrapService.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace rt_bootstrap {
|
||||
|
||||
class ExecutorSharedMemoryMapperService final
|
||||
: public ExecutorBootstrapService {
|
||||
public:
|
||||
~ExecutorSharedMemoryMapperService(){};
|
||||
|
||||
Expected<std::pair<ExecutorAddr, std::string>> reserve(uint64_t Size);
|
||||
Expected<ExecutorAddr> initialize(ExecutorAddr Reservation,
|
||||
tpctypes::SharedMemoryFinalizeRequest &FR);
|
||||
|
||||
Error deinitialize(const std::vector<ExecutorAddr> &Bases);
|
||||
Error release(const std::vector<ExecutorAddr> &Bases);
|
||||
|
||||
Error shutdown() override;
|
||||
void addBootstrapSymbols(StringMap<ExecutorAddr> &M) override;
|
||||
|
||||
private:
|
||||
struct Allocation {
|
||||
std::vector<shared::WrapperFunctionCall> DeinitializationActions;
|
||||
};
|
||||
using AllocationMap = DenseMap<ExecutorAddr, Allocation>;
|
||||
|
||||
struct Reservation {
|
||||
size_t Size;
|
||||
std::vector<ExecutorAddr> Allocations;
|
||||
#if defined(_WIN32)
|
||||
HANDLE SharedMemoryFile;
|
||||
#endif
|
||||
};
|
||||
using ReservationMap = DenseMap<void *, Reservation>;
|
||||
|
||||
static llvm::orc::shared::CWrapperFunctionResult
|
||||
reserveWrapper(const char *ArgData, size_t ArgSize);
|
||||
|
||||
static llvm::orc::shared::CWrapperFunctionResult
|
||||
initializeWrapper(const char *ArgData, size_t ArgSize);
|
||||
|
||||
static llvm::orc::shared::CWrapperFunctionResult
|
||||
deinitializeWrapper(const char *ArgData, size_t ArgSize);
|
||||
|
||||
static llvm::orc::shared::CWrapperFunctionResult
|
||||
releaseWrapper(const char *ArgData, size_t ArgSize);
|
||||
|
||||
std::atomic<int> SharedMemoryCount{0};
|
||||
std::mutex Mutex;
|
||||
ReservationMap Reservations;
|
||||
AllocationMap Allocations;
|
||||
};
|
||||
|
||||
} // namespace rt_bootstrap
|
||||
} // namespace orc
|
||||
} // namespace llvm
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_EXECUTORSHAREDMEMORYMAPPERSERVICE
|
|
@ -1,3 +1,7 @@
|
|||
if( CMAKE_HOST_UNIX AND HAVE_LIBRT )
|
||||
set(rt_lib rt)
|
||||
endif()
|
||||
|
||||
add_llvm_component_library(LLVMOrcJIT
|
||||
CompileOnDemandLayer.cpp
|
||||
CompileUtils.cpp
|
||||
|
@ -45,6 +49,7 @@ add_llvm_component_library(LLVMOrcJIT
|
|||
|
||||
LINK_LIBS
|
||||
${LLVM_PTHREAD_LIB}
|
||||
${rt_lib}
|
||||
|
||||
LINK_COMPONENTS
|
||||
Core
|
||||
|
|
|
@ -8,6 +8,17 @@
|
|||
|
||||
#include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
|
||||
#include "llvm/Support/WindowsError.h"
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
|
@ -147,6 +158,225 @@ InProcessMemoryMapper::~InProcessMemoryMapper() {
|
|||
cantFail(F.get());
|
||||
}
|
||||
|
||||
// SharedMemoryMapper
|
||||
|
||||
void SharedMemoryMapper::reserve(size_t NumBytes,
|
||||
OnReservedFunction OnReserved) {
|
||||
#if defined(LLVM_ON_UNIX) || defined(_WIN32)
|
||||
|
||||
EPC.callSPSWrapperAsync<
|
||||
rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>(
|
||||
SAs.Reserve,
|
||||
[this, NumBytes, OnReserved = std::move(OnReserved)](
|
||||
Error SerializationErr,
|
||||
Expected<std::pair<ExecutorAddr, std::string>> Result) mutable {
|
||||
if (SerializationErr) {
|
||||
cantFail(Result.takeError());
|
||||
return OnReserved(std::move(SerializationErr));
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
return OnReserved(Result.takeError());
|
||||
|
||||
ExecutorAddr RemoteAddr;
|
||||
std::string SharedMemoryName;
|
||||
std::tie(RemoteAddr, SharedMemoryName) = std::move(*Result);
|
||||
|
||||
void *LocalAddr = nullptr;
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
|
||||
int SharedMemoryFile = shm_open(SharedMemoryName.c_str(), O_RDWR, 0700);
|
||||
if (SharedMemoryFile < 0) {
|
||||
return OnReserved(errorCodeToError(
|
||||
std::error_code(errno, std::generic_category())));
|
||||
}
|
||||
|
||||
// this prevents other processes from accessing it by name
|
||||
shm_unlink(SharedMemoryName.c_str());
|
||||
|
||||
LocalAddr = mmap(nullptr, NumBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
SharedMemoryFile, 0);
|
||||
if (LocalAddr == MAP_FAILED) {
|
||||
return OnReserved(errorCodeToError(
|
||||
std::error_code(errno, std::generic_category())));
|
||||
}
|
||||
|
||||
close(SharedMemoryFile);
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
|
||||
SharedMemoryName.end());
|
||||
HANDLE SharedMemoryFile = OpenFileMappingW(
|
||||
FILE_MAP_ALL_ACCESS, FALSE, WideSharedMemoryName.c_str());
|
||||
if (!SharedMemoryFile)
|
||||
return OnReserved(errorCodeToError(mapWindowsError(GetLastError())));
|
||||
|
||||
LocalAddr =
|
||||
MapViewOfFile(SharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
if (!LocalAddr) {
|
||||
CloseHandle(SharedMemoryFile);
|
||||
return OnReserved(errorCodeToError(mapWindowsError(GetLastError())));
|
||||
}
|
||||
|
||||
CloseHandle(SharedMemoryFile);
|
||||
|
||||
#endif
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
Reservations.insert({RemoteAddr, {LocalAddr, NumBytes}});
|
||||
}
|
||||
|
||||
OnReserved(ExecutorAddrRange(RemoteAddr, NumBytes));
|
||||
},
|
||||
SAs.Instance, static_cast<uint64_t>(NumBytes));
|
||||
|
||||
#else
|
||||
OnReserved(make_error<StringError>(
|
||||
"SharedMemoryMapper is not supported on this platform yet",
|
||||
inconvertibleErrorCode()));
|
||||
#endif
|
||||
}
|
||||
|
||||
char *SharedMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) {
|
||||
auto R = Reservations.upper_bound(Addr);
|
||||
assert(R != Reservations.begin() && "Attempt to prepare unknown range");
|
||||
R--;
|
||||
|
||||
ExecutorAddrDiff Offset = Addr - R->first;
|
||||
|
||||
return static_cast<char *>(R->second.LocalAddr) + Offset;
|
||||
}
|
||||
|
||||
void SharedMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,
|
||||
OnInitializedFunction OnInitialized) {
|
||||
auto Reservation = Reservations.find(AI.MappingBase);
|
||||
assert(Reservation != Reservations.end() &&
|
||||
"Attempt to initialize unreserved range");
|
||||
|
||||
tpctypes::SharedMemoryFinalizeRequest FR;
|
||||
|
||||
AI.Actions.swap(FR.Actions);
|
||||
|
||||
FR.Segments.reserve(AI.Segments.size());
|
||||
|
||||
for (auto Segment : AI.Segments) {
|
||||
char *Base =
|
||||
static_cast<char *>(Reservation->second.LocalAddr) + Segment.Offset;
|
||||
std::memset(Base + Segment.ContentSize, 0, Segment.ZeroFillSize);
|
||||
|
||||
tpctypes::SharedMemorySegFinalizeRequest SegReq;
|
||||
SegReq.Prot = tpctypes::toWireProtectionFlags(
|
||||
static_cast<sys::Memory::ProtectionFlags>(Segment.Prot));
|
||||
SegReq.Addr = AI.MappingBase + Segment.Offset;
|
||||
SegReq.Size = Segment.ContentSize + Segment.ZeroFillSize;
|
||||
|
||||
FR.Segments.push_back(SegReq);
|
||||
}
|
||||
|
||||
EPC.callSPSWrapperAsync<
|
||||
rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>(
|
||||
SAs.Initialize,
|
||||
[OnInitialized = std::move(OnInitialized)](
|
||||
Error SerializationErr, Expected<ExecutorAddr> Result) mutable {
|
||||
if (SerializationErr) {
|
||||
cantFail(Result.takeError());
|
||||
return OnInitialized(std::move(SerializationErr));
|
||||
}
|
||||
|
||||
OnInitialized(std::move(Result));
|
||||
},
|
||||
SAs.Instance, AI.MappingBase, std::move(FR));
|
||||
}
|
||||
|
||||
void SharedMemoryMapper::deinitialize(
|
||||
ArrayRef<ExecutorAddr> Allocations,
|
||||
MemoryMapper::OnDeinitializedFunction OnDeinitialized) {
|
||||
EPC.callSPSWrapperAsync<
|
||||
rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>(
|
||||
SAs.Deinitialize,
|
||||
[OnDeinitialized = std::move(OnDeinitialized)](Error SerializationErr,
|
||||
Error Result) mutable {
|
||||
if (SerializationErr) {
|
||||
cantFail(std::move(Result));
|
||||
return OnDeinitialized(std::move(SerializationErr));
|
||||
}
|
||||
|
||||
OnDeinitialized(std::move(Result));
|
||||
},
|
||||
SAs.Instance, Allocations);
|
||||
}
|
||||
|
||||
void SharedMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,
|
||||
OnReleasedFunction OnReleased) {
|
||||
#if defined(LLVM_ON_UNIX) || defined(_WIN32)
|
||||
Error Err = Error::success();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
|
||||
for (auto Base : Bases) {
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
|
||||
if (munmap(Reservations[Base].LocalAddr, Reservations[Base].Size) != 0)
|
||||
Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
|
||||
errno, std::generic_category())));
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
if (!UnmapViewOfFile(Reservations[Base].LocalAddr))
|
||||
joinErrors(std::move(Err),
|
||||
errorCodeToError(mapWindowsError(GetLastError())));
|
||||
|
||||
#endif
|
||||
|
||||
Reservations.erase(Base);
|
||||
}
|
||||
}
|
||||
|
||||
EPC.callSPSWrapperAsync<
|
||||
rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>(
|
||||
SAs.Release,
|
||||
[OnReleased = std::move(OnReleased),
|
||||
Err = std::move(Err)](Error SerializationErr, Error Result) mutable {
|
||||
if (SerializationErr) {
|
||||
cantFail(std::move(Result));
|
||||
return OnReleased(
|
||||
joinErrors(std::move(Err), std::move(SerializationErr)));
|
||||
}
|
||||
|
||||
return OnReleased(joinErrors(std::move(Err), std::move(Result)));
|
||||
},
|
||||
SAs.Instance, Bases);
|
||||
#else
|
||||
OnReleased(make_error<StringError>(
|
||||
"SharedMemoryMapper is not supported on this platform yet",
|
||||
inconvertibleErrorCode()));
|
||||
#endif
|
||||
}
|
||||
|
||||
SharedMemoryMapper::~SharedMemoryMapper() {
|
||||
std::vector<ExecutorAddr> ReservationAddrs;
|
||||
if (!Reservations.empty()) {
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
{
|
||||
ReservationAddrs.reserve(Reservations.size());
|
||||
for (const auto &R : Reservations) {
|
||||
ReservationAddrs.push_back(R.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::promise<MSVCPError> P;
|
||||
auto F = P.get_future();
|
||||
release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
|
||||
// FIXME: Release can actually fail. The error should be propagated.
|
||||
// Meanwhile, a better option is to explicitly call release().
|
||||
cantFail(F.get());
|
||||
}
|
||||
|
||||
} // namespace orc
|
||||
|
||||
} // namespace llvm
|
||||
|
|
|
@ -18,6 +18,7 @@ const char *SimpleExecutorDylibManagerOpenWrapperName =
|
|||
"__llvm_orc_SimpleExecutorDylibManager_open_wrapper";
|
||||
const char *SimpleExecutorDylibManagerLookupWrapperName =
|
||||
"__llvm_orc_SimpleExecutorDylibManager_lookup_wrapper";
|
||||
|
||||
const char *SimpleExecutorMemoryManagerInstanceName =
|
||||
"__llvm_orc_SimpleExecutorMemoryManager_Instance";
|
||||
const char *SimpleExecutorMemoryManagerReserveWrapperName =
|
||||
|
@ -26,6 +27,18 @@ const char *SimpleExecutorMemoryManagerFinalizeWrapperName =
|
|||
"__llvm_orc_SimpleExecutorMemoryManager_finalize_wrapper";
|
||||
const char *SimpleExecutorMemoryManagerDeallocateWrapperName =
|
||||
"__llvm_orc_SimpleExecutorMemoryManager_deallocate_wrapper";
|
||||
|
||||
const char *ExecutorSharedMemoryMapperServiceInstanceName =
|
||||
"__llvm_orc_ExecutorSharedMemoryMapperService_Instance";
|
||||
const char *ExecutorSharedMemoryMapperServiceReserveWrapperName =
|
||||
"__llvm_orc_ExecutorSharedMemoryMapperService_Reserve";
|
||||
const char *ExecutorSharedMemoryMapperServiceInitializeWrapperName =
|
||||
"__llvm_orc_ExecutorSharedMemoryMapperService_Initialize";
|
||||
const char *ExecutorSharedMemoryMapperServiceDeinitializeWrapperName =
|
||||
"__llvm_orc_ExecutorSharedMemoryMapperService_Deinitialize";
|
||||
const char *ExecutorSharedMemoryMapperServiceReleaseWrapperName =
|
||||
"__llvm_orc_ExecutorSharedMemoryMapperService_Release";
|
||||
|
||||
const char *MemoryWriteUInt8sWrapperName =
|
||||
"__llvm_orc_bootstrap_mem_write_uint8s_wrapper";
|
||||
const char *MemoryWriteUInt16sWrapperName =
|
||||
|
@ -36,10 +49,12 @@ const char *MemoryWriteUInt64sWrapperName =
|
|||
"__llvm_orc_bootstrap_mem_write_uint64s_wrapper";
|
||||
const char *MemoryWriteBuffersWrapperName =
|
||||
"__llvm_orc_bootstrap_mem_write_buffers_wrapper";
|
||||
|
||||
const char *RegisterEHFrameSectionWrapperName =
|
||||
"__llvm_orc_bootstrap_register_ehframe_section_wrapper";
|
||||
const char *DeregisterEHFrameSectionWrapperName =
|
||||
"__llvm_orc_bootstrap_deregister_ehframe_section_wrapper";
|
||||
|
||||
const char *RunAsMainWrapperName = "__llvm_orc_bootstrap_run_as_main_wrapper";
|
||||
|
||||
} // end namespace rt
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
if( CMAKE_HOST_UNIX AND HAVE_LIBRT )
|
||||
set(rt_lib rt)
|
||||
endif()
|
||||
|
||||
add_llvm_component_library(LLVMOrcTargetProcess
|
||||
ExecutorSharedMemoryMapperService.cpp
|
||||
JITLoaderGDB.cpp
|
||||
OrcRTBootstrap.cpp
|
||||
RegisterEHFrames.cpp
|
||||
|
@ -12,6 +17,7 @@ add_llvm_component_library(LLVMOrcTargetProcess
|
|||
|
||||
LINK_LIBS
|
||||
${LLVM_PTHREAD_LIB}
|
||||
${rt_lib}
|
||||
|
||||
LINK_COMPONENTS
|
||||
OrcShared
|
||||
|
|
|
@ -0,0 +1,341 @@
|
|||
//===---------- ExecutorSharedMemoryMapperService.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 "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h"
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/WindowsError.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
static DWORD getWindowsProtectionFlags(unsigned Flags) {
|
||||
switch (Flags & llvm::sys::Memory::MF_RWE_MASK) {
|
||||
case llvm::sys::Memory::MF_READ:
|
||||
return PAGE_READONLY;
|
||||
case llvm::sys::Memory::MF_WRITE:
|
||||
// Note: PAGE_WRITE is not supported by VirtualProtect
|
||||
return PAGE_READWRITE;
|
||||
case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE:
|
||||
return PAGE_READWRITE;
|
||||
case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_EXEC:
|
||||
return PAGE_EXECUTE_READ;
|
||||
case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE |
|
||||
llvm::sys::Memory::MF_EXEC:
|
||||
return PAGE_EXECUTE_READWRITE;
|
||||
case llvm::sys::Memory::MF_EXEC:
|
||||
return PAGE_EXECUTE;
|
||||
default:
|
||||
llvm_unreachable("Illegal memory protection flag specified!");
|
||||
}
|
||||
// Provide a default return value as required by some compilers.
|
||||
return PAGE_NOACCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace rt_bootstrap {
|
||||
|
||||
Expected<std::pair<ExecutorAddr, std::string>>
|
||||
ExecutorSharedMemoryMapperService::reserve(uint64_t Size) {
|
||||
#if defined(LLVM_ON_UNIX) || defined(_WIN32)
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
|
||||
std::string SharedMemoryName;
|
||||
{
|
||||
std::stringstream SharedMemoryNameStream;
|
||||
SharedMemoryNameStream << "/jitlink_" << sys::Process::getProcessId() << '_'
|
||||
<< (++SharedMemoryCount);
|
||||
SharedMemoryName = SharedMemoryNameStream.str();
|
||||
}
|
||||
|
||||
int SharedMemoryFile =
|
||||
shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0700);
|
||||
if (SharedMemoryFile < 0)
|
||||
return errorCodeToError(std::error_code(errno, std::generic_category()));
|
||||
|
||||
// by default size is 0
|
||||
if (ftruncate(SharedMemoryFile, Size) < 0)
|
||||
return errorCodeToError(std::error_code(errno, std::generic_category()));
|
||||
|
||||
void *Addr = mmap(nullptr, Size, PROT_NONE, MAP_SHARED, SharedMemoryFile, 0);
|
||||
if (Addr == MAP_FAILED)
|
||||
return errorCodeToError(std::error_code(errno, std::generic_category()));
|
||||
|
||||
close(SharedMemoryFile);
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
std::string SharedMemoryName;
|
||||
{
|
||||
std::stringstream SharedMemoryNameStream;
|
||||
SharedMemoryNameStream << "jitlink_" << sys::Process::getProcessId() << '_'
|
||||
<< (++SharedMemoryCount);
|
||||
SharedMemoryName = SharedMemoryNameStream.str();
|
||||
}
|
||||
|
||||
std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
|
||||
SharedMemoryName.end());
|
||||
HANDLE SharedMemoryFile = CreateFileMappingW(
|
||||
INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, Size >> 32,
|
||||
Size & 0xffffffff, WideSharedMemoryName.c_str());
|
||||
if (!SharedMemoryFile)
|
||||
return errorCodeToError(mapWindowsError(GetLastError()));
|
||||
|
||||
void *Addr = MapViewOfFile(SharedMemoryFile,
|
||||
FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);
|
||||
if (!Addr) {
|
||||
CloseHandle(SharedMemoryFile);
|
||||
return errorCodeToError(mapWindowsError(GetLastError()));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
Reservations[Addr].Size = Size;
|
||||
#if defined(_WIN32)
|
||||
Reservations[Addr].SharedMemoryFile = SharedMemoryFile;
|
||||
#endif
|
||||
}
|
||||
|
||||
return std::make_pair(ExecutorAddr::fromPtr(Addr),
|
||||
std::move(SharedMemoryName));
|
||||
#else
|
||||
return make_error<StringError>(
|
||||
"SharedMemoryMapper is not supported on this platform yet",
|
||||
inconvertibleErrorCode());
|
||||
#endif
|
||||
}
|
||||
|
||||
Expected<ExecutorAddr> ExecutorSharedMemoryMapperService::initialize(
|
||||
ExecutorAddr Reservation, tpctypes::SharedMemoryFinalizeRequest &FR) {
|
||||
#if defined(LLVM_ON_UNIX) || defined(_WIN32)
|
||||
|
||||
ExecutorAddr MinAddr(~0ULL);
|
||||
|
||||
// Contents are already in place
|
||||
for (auto &Segment : FR.Segments) {
|
||||
if (Segment.Addr < MinAddr)
|
||||
MinAddr = Segment.Addr;
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
|
||||
int NativeProt = 0;
|
||||
if (Segment.Prot & tpctypes::WPF_Read)
|
||||
NativeProt |= PROT_READ;
|
||||
if (Segment.Prot & tpctypes::WPF_Write)
|
||||
NativeProt |= PROT_WRITE;
|
||||
if (Segment.Prot & tpctypes::WPF_Exec)
|
||||
NativeProt |= PROT_EXEC;
|
||||
|
||||
if (mprotect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt))
|
||||
return errorCodeToError(std::error_code(errno, std::generic_category()));
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
DWORD NativeProt =
|
||||
getWindowsProtectionFlags(fromWireProtectionFlags(Segment.Prot));
|
||||
|
||||
if (!VirtualProtect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt,
|
||||
&NativeProt))
|
||||
return errorCodeToError(mapWindowsError(GetLastError()));
|
||||
|
||||
#endif
|
||||
|
||||
if (Segment.Prot & tpctypes::WPF_Exec)
|
||||
sys::Memory::InvalidateInstructionCache(Segment.Addr.toPtr<void *>(),
|
||||
Segment.Size);
|
||||
}
|
||||
|
||||
// Run finalization actions and get deinitlization action list.
|
||||
auto DeinitializeActions = shared::runFinalizeActions(FR.Actions);
|
||||
if (!DeinitializeActions) {
|
||||
return DeinitializeActions.takeError();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
Allocations[MinAddr].DeinitializationActions =
|
||||
std::move(*DeinitializeActions);
|
||||
Reservations[Reservation.toPtr<void *>()].Allocations.push_back(MinAddr);
|
||||
}
|
||||
|
||||
return MinAddr;
|
||||
|
||||
#else
|
||||
return make_error<StringError>(
|
||||
"SharedMemoryMapper is not supported on this platform yet",
|
||||
inconvertibleErrorCode());
|
||||
#endif
|
||||
}
|
||||
|
||||
Error ExecutorSharedMemoryMapperService::deinitialize(
|
||||
const std::vector<ExecutorAddr> &Bases) {
|
||||
Error AllErr = Error::success();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
|
||||
for (auto Base : Bases) {
|
||||
if (Error Err = shared::runDeallocActions(
|
||||
Allocations[Base].DeinitializationActions)) {
|
||||
AllErr = joinErrors(std::move(AllErr), std::move(Err));
|
||||
}
|
||||
|
||||
Allocations.erase(Base);
|
||||
}
|
||||
}
|
||||
|
||||
return AllErr;
|
||||
}
|
||||
|
||||
Error ExecutorSharedMemoryMapperService::release(
|
||||
const std::vector<ExecutorAddr> &Bases) {
|
||||
#if defined(LLVM_ON_UNIX) || defined(_WIN32)
|
||||
Error Err = Error::success();
|
||||
|
||||
for (auto Base : Bases) {
|
||||
std::vector<ExecutorAddr> AllocAddrs;
|
||||
size_t Size;
|
||||
|
||||
#if defined(_WIN32)
|
||||
HANDLE SharedMemoryFile;
|
||||
#endif
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
auto &R = Reservations[Base.toPtr<void *>()];
|
||||
Size = R.Size;
|
||||
|
||||
#if defined(_WIN32)
|
||||
SharedMemoryFile = R.SharedMemoryFile;
|
||||
#endif
|
||||
|
||||
AllocAddrs.swap(R.Allocations);
|
||||
}
|
||||
|
||||
// deinitialize sub allocations
|
||||
if (Error E = deinitialize(AllocAddrs))
|
||||
Err = joinErrors(std::move(Err), std::move(E));
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
|
||||
if (munmap(Base.toPtr<void *>(), Size) != 0)
|
||||
Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
|
||||
errno, std::generic_category())));
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
if (!UnmapViewOfFile(Base.toPtr<void *>()))
|
||||
Err = joinErrors(std::move(Err),
|
||||
errorCodeToError(mapWindowsError(GetLastError())));
|
||||
|
||||
CloseHandle(SharedMemoryFile);
|
||||
|
||||
#endif
|
||||
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
Reservations.erase(Base.toPtr<void *>());
|
||||
}
|
||||
|
||||
return Err;
|
||||
#else
|
||||
return make_error<StringError>(
|
||||
"SharedMemoryMapper is not supported on this platform yet",
|
||||
inconvertibleErrorCode());
|
||||
#endif
|
||||
}
|
||||
|
||||
Error ExecutorSharedMemoryMapperService::shutdown() {
|
||||
std::vector<ExecutorAddr> ReservationAddrs;
|
||||
if (!Reservations.empty()) {
|
||||
std::lock_guard<std::mutex> Lock(Mutex);
|
||||
{
|
||||
ReservationAddrs.reserve(Reservations.size());
|
||||
for (const auto &R : Reservations) {
|
||||
ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return release(ReservationAddrs);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void ExecutorSharedMemoryMapperService::addBootstrapSymbols(
|
||||
StringMap<ExecutorAddr> &M) {
|
||||
M[rt::ExecutorSharedMemoryMapperServiceInstanceName] =
|
||||
ExecutorAddr::fromPtr(this);
|
||||
M[rt::ExecutorSharedMemoryMapperServiceReserveWrapperName] =
|
||||
ExecutorAddr::fromPtr(&reserveWrapper);
|
||||
M[rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName] =
|
||||
ExecutorAddr::fromPtr(&initializeWrapper);
|
||||
M[rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName] =
|
||||
ExecutorAddr::fromPtr(&deinitializeWrapper);
|
||||
M[rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName] =
|
||||
ExecutorAddr::fromPtr(&releaseWrapper);
|
||||
}
|
||||
|
||||
llvm::orc::shared::CWrapperFunctionResult
|
||||
ExecutorSharedMemoryMapperService::reserveWrapper(const char *ArgData,
|
||||
size_t ArgSize) {
|
||||
return shared::WrapperFunction<
|
||||
rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>::
|
||||
handle(ArgData, ArgSize,
|
||||
shared::makeMethodWrapperHandler(
|
||||
&ExecutorSharedMemoryMapperService::reserve))
|
||||
.release();
|
||||
}
|
||||
|
||||
llvm::orc::shared::CWrapperFunctionResult
|
||||
ExecutorSharedMemoryMapperService::initializeWrapper(const char *ArgData,
|
||||
size_t ArgSize) {
|
||||
return shared::WrapperFunction<
|
||||
rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>::
|
||||
handle(ArgData, ArgSize,
|
||||
shared::makeMethodWrapperHandler(
|
||||
&ExecutorSharedMemoryMapperService::initialize))
|
||||
.release();
|
||||
}
|
||||
|
||||
llvm::orc::shared::CWrapperFunctionResult
|
||||
ExecutorSharedMemoryMapperService::deinitializeWrapper(const char *ArgData,
|
||||
size_t ArgSize) {
|
||||
return shared::WrapperFunction<
|
||||
rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>::
|
||||
handle(ArgData, ArgSize,
|
||||
shared::makeMethodWrapperHandler(
|
||||
&ExecutorSharedMemoryMapperService::deinitialize))
|
||||
.release();
|
||||
}
|
||||
|
||||
llvm::orc::shared::CWrapperFunctionResult
|
||||
ExecutorSharedMemoryMapperService::releaseWrapper(const char *ArgData,
|
||||
size_t ArgSize) {
|
||||
return shared::WrapperFunction<
|
||||
rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>::
|
||||
handle(ArgData, ArgSize,
|
||||
shared::makeMethodWrapperHandler(
|
||||
&ExecutorSharedMemoryMapperService::release))
|
||||
.release();
|
||||
}
|
||||
|
||||
} // namespace rt_bootstrap
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
|
@ -30,6 +30,7 @@ add_llvm_unittest(OrcJITTests
|
|||
OrcTestCommon.cpp
|
||||
ResourceTrackerTest.cpp
|
||||
RTDyldObjectLinkingLayerTest.cpp
|
||||
SharedMemoryMapperTest.cpp
|
||||
SimpleExecutorMemoryManagerTest.cpp
|
||||
SimplePackedSerializationTest.cpp
|
||||
SymbolStringPoolTest.cpp
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
//===- SharedMemoryMapperTest.cpp -- Tests for SharedMemoryMapper ---------===//
|
||||
//
|
||||
// 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 "OrcTestCommon.h"
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h"
|
||||
#include "llvm/Testing/Support/Error.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::orc;
|
||||
using namespace llvm::orc::shared;
|
||||
using namespace llvm::orc::rt_bootstrap;
|
||||
|
||||
#if defined(LLVM_ON_UNIX) || defined(_WIN32)
|
||||
|
||||
// A basic function to be used as both initializer/deinitializer
|
||||
orc::shared::CWrapperFunctionResult incrementWrapper(const char *ArgData,
|
||||
size_t ArgSize) {
|
||||
return WrapperFunction<SPSError(SPSExecutorAddr)>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](ExecutorAddr A) -> Error {
|
||||
*A.toPtr<int *>() += 1;
|
||||
return Error::success();
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
TEST(SharedMemoryMapperTest, MemReserveInitializeDeinitializeRelease) {
|
||||
// These counters are used to track how many times the initializer and
|
||||
// deinitializer functions are called
|
||||
int InitializeCounter = 0;
|
||||
int DeinitializeCounter = 0;
|
||||
|
||||
auto SelfEPC = cantFail(SelfExecutorProcessControl::Create());
|
||||
|
||||
ExecutorSharedMemoryMapperService MapperService;
|
||||
|
||||
SharedMemoryMapper::SymbolAddrs SAs;
|
||||
{
|
||||
StringMap<ExecutorAddr> Map;
|
||||
MapperService.addBootstrapSymbols(Map);
|
||||
SAs.Instance = Map[rt::ExecutorSharedMemoryMapperServiceInstanceName];
|
||||
SAs.Reserve = Map[rt::ExecutorSharedMemoryMapperServiceReserveWrapperName];
|
||||
SAs.Initialize =
|
||||
Map[rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName];
|
||||
SAs.Deinitialize =
|
||||
Map[rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName];
|
||||
SAs.Release = Map[rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName];
|
||||
}
|
||||
|
||||
std::string TestString = "Hello, World!";
|
||||
|
||||
// barrier
|
||||
std::promise<void> P;
|
||||
auto F = P.get_future();
|
||||
|
||||
{
|
||||
auto PageSize = cantFail(sys::Process::getPageSize());
|
||||
size_t ReqSize = PageSize;
|
||||
|
||||
std::unique_ptr<MemoryMapper> Mapper =
|
||||
std::make_unique<SharedMemoryMapper>(*SelfEPC, SAs);
|
||||
|
||||
Mapper->reserve(ReqSize, [&](Expected<ExecutorAddrRange> Result) {
|
||||
EXPECT_THAT_ERROR(Result.takeError(), Succeeded());
|
||||
auto Reservation = std::move(*Result);
|
||||
{
|
||||
char *Addr = Mapper->prepare(Reservation.Start, TestString.size() + 1);
|
||||
std::strcpy(Addr, TestString.c_str());
|
||||
}
|
||||
MemoryMapper::AllocInfo AI;
|
||||
{
|
||||
MemoryMapper::AllocInfo::SegInfo SI;
|
||||
SI.Offset = 0;
|
||||
SI.ContentSize = TestString.size() + 1;
|
||||
SI.ZeroFillSize = PageSize - SI.ContentSize;
|
||||
SI.Prot = sys::Memory::MF_READ | sys::Memory::MF_WRITE;
|
||||
|
||||
AI.MappingBase = Reservation.Start;
|
||||
AI.Segments.push_back(SI);
|
||||
AI.Actions.push_back(
|
||||
{cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
|
||||
ExecutorAddr::fromPtr(incrementWrapper),
|
||||
ExecutorAddr::fromPtr(&InitializeCounter))),
|
||||
cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
|
||||
ExecutorAddr::fromPtr(incrementWrapper),
|
||||
ExecutorAddr::fromPtr(&DeinitializeCounter)))});
|
||||
}
|
||||
|
||||
EXPECT_EQ(InitializeCounter, 0);
|
||||
EXPECT_EQ(DeinitializeCounter, 0);
|
||||
|
||||
Mapper->initialize(AI, [&, Reservation](Expected<ExecutorAddr> Result) {
|
||||
EXPECT_THAT_ERROR(Result.takeError(), Succeeded());
|
||||
|
||||
EXPECT_EQ(TestString, std::string(static_cast<char *>(
|
||||
Reservation.Start.toPtr<char *>())));
|
||||
|
||||
EXPECT_EQ(InitializeCounter, 1);
|
||||
EXPECT_EQ(DeinitializeCounter, 0);
|
||||
|
||||
Mapper->deinitialize({*Result}, [&, Reservation](Error Err) {
|
||||
EXPECT_THAT_ERROR(std::move(Err), Succeeded());
|
||||
|
||||
EXPECT_EQ(InitializeCounter, 1);
|
||||
EXPECT_EQ(DeinitializeCounter, 1);
|
||||
|
||||
Mapper->release({Reservation.Start}, [&](Error Err) {
|
||||
EXPECT_THAT_ERROR(std::move(Err), Succeeded());
|
||||
|
||||
P.set_value();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// This will block the test if any of the above callbacks are not executed
|
||||
F.wait();
|
||||
// Mapper must be destructed before calling shutdown to avoid double free
|
||||
}
|
||||
|
||||
EXPECT_THAT_ERROR(MapperService.shutdown(), Succeeded());
|
||||
cantFail(SelfEPC->disconnect());
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue