MemoryMapper.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. //===- MemoryMapper.cpp - Cross-process memory mapper ------------*- 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. #include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
  9. #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
  10. #include "llvm/Support/WindowsError.h"
  11. #include <algorithm>
  12. #if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)
  13. #include <fcntl.h>
  14. #include <sys/mman.h>
  15. #include <unistd.h>
  16. #elif defined(_WIN32)
  17. #include <windows.h>
  18. #endif
  19. namespace llvm {
  20. namespace orc {
  21. MemoryMapper::~MemoryMapper() {}
  22. InProcessMemoryMapper::InProcessMemoryMapper(size_t PageSize)
  23. : PageSize(PageSize) {}
  24. Expected<std::unique_ptr<InProcessMemoryMapper>>
  25. InProcessMemoryMapper::Create() {
  26. auto PageSize = sys::Process::getPageSize();
  27. if (!PageSize)
  28. return PageSize.takeError();
  29. return std::make_unique<InProcessMemoryMapper>(*PageSize);
  30. }
  31. void InProcessMemoryMapper::reserve(size_t NumBytes,
  32. OnReservedFunction OnReserved) {
  33. std::error_code EC;
  34. auto MB = sys::Memory::allocateMappedMemory(
  35. NumBytes, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
  36. if (EC)
  37. return OnReserved(errorCodeToError(EC));
  38. {
  39. std::lock_guard<std::mutex> Lock(Mutex);
  40. Reservations[MB.base()].Size = MB.allocatedSize();
  41. }
  42. OnReserved(
  43. ExecutorAddrRange(ExecutorAddr::fromPtr(MB.base()), MB.allocatedSize()));
  44. }
  45. char *InProcessMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) {
  46. return Addr.toPtr<char *>();
  47. }
  48. void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,
  49. OnInitializedFunction OnInitialized) {
  50. ExecutorAddr MinAddr(~0ULL);
  51. ExecutorAddr MaxAddr(0);
  52. // FIXME: Release finalize lifetime segments.
  53. for (auto &Segment : AI.Segments) {
  54. auto Base = AI.MappingBase + Segment.Offset;
  55. auto Size = Segment.ContentSize + Segment.ZeroFillSize;
  56. if (Base < MinAddr)
  57. MinAddr = Base;
  58. if (Base + Size > MaxAddr)
  59. MaxAddr = Base + Size;
  60. std::memset((Base + Segment.ContentSize).toPtr<void *>(), 0,
  61. Segment.ZeroFillSize);
  62. if (auto EC = sys::Memory::protectMappedMemory(
  63. {Base.toPtr<void *>(), Size},
  64. toSysMemoryProtectionFlags(Segment.AG.getMemProt()))) {
  65. return OnInitialized(errorCodeToError(EC));
  66. }
  67. if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)
  68. sys::Memory::InvalidateInstructionCache(Base.toPtr<void *>(), Size);
  69. }
  70. auto DeinitializeActions = shared::runFinalizeActions(AI.Actions);
  71. if (!DeinitializeActions)
  72. return OnInitialized(DeinitializeActions.takeError());
  73. {
  74. std::lock_guard<std::mutex> Lock(Mutex);
  75. // This is the maximum range whose permission have been possibly modified
  76. Allocations[MinAddr].Size = MaxAddr - MinAddr;
  77. Allocations[MinAddr].DeinitializationActions =
  78. std::move(*DeinitializeActions);
  79. Reservations[AI.MappingBase.toPtr<void *>()].Allocations.push_back(MinAddr);
  80. }
  81. OnInitialized(MinAddr);
  82. }
  83. void InProcessMemoryMapper::deinitialize(
  84. ArrayRef<ExecutorAddr> Bases,
  85. MemoryMapper::OnDeinitializedFunction OnDeinitialized) {
  86. Error AllErr = Error::success();
  87. {
  88. std::lock_guard<std::mutex> Lock(Mutex);
  89. for (auto Base : llvm::reverse(Bases)) {
  90. if (Error Err = shared::runDeallocActions(
  91. Allocations[Base].DeinitializationActions)) {
  92. AllErr = joinErrors(std::move(AllErr), std::move(Err));
  93. }
  94. // Reset protections to read/write so the area can be reused
  95. if (auto EC = sys::Memory::protectMappedMemory(
  96. {Base.toPtr<void *>(), Allocations[Base].Size},
  97. sys::Memory::ProtectionFlags::MF_READ |
  98. sys::Memory::ProtectionFlags::MF_WRITE)) {
  99. AllErr = joinErrors(std::move(AllErr), errorCodeToError(EC));
  100. }
  101. Allocations.erase(Base);
  102. }
  103. }
  104. OnDeinitialized(std::move(AllErr));
  105. }
  106. void InProcessMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,
  107. OnReleasedFunction OnReleased) {
  108. Error Err = Error::success();
  109. for (auto Base : Bases) {
  110. std::vector<ExecutorAddr> AllocAddrs;
  111. size_t Size;
  112. {
  113. std::lock_guard<std::mutex> Lock(Mutex);
  114. auto &R = Reservations[Base.toPtr<void *>()];
  115. Size = R.Size;
  116. AllocAddrs.swap(R.Allocations);
  117. }
  118. // deinitialize sub allocations
  119. std::promise<MSVCPError> P;
  120. auto F = P.get_future();
  121. deinitialize(AllocAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
  122. if (Error E = F.get()) {
  123. Err = joinErrors(std::move(Err), std::move(E));
  124. }
  125. // free the memory
  126. auto MB = sys::MemoryBlock(Base.toPtr<void *>(), Size);
  127. auto EC = sys::Memory::releaseMappedMemory(MB);
  128. if (EC) {
  129. Err = joinErrors(std::move(Err), errorCodeToError(EC));
  130. }
  131. std::lock_guard<std::mutex> Lock(Mutex);
  132. Reservations.erase(Base.toPtr<void *>());
  133. }
  134. OnReleased(std::move(Err));
  135. }
  136. InProcessMemoryMapper::~InProcessMemoryMapper() {
  137. std::vector<ExecutorAddr> ReservationAddrs;
  138. {
  139. std::lock_guard<std::mutex> Lock(Mutex);
  140. ReservationAddrs.reserve(Reservations.size());
  141. for (const auto &R : Reservations) {
  142. ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
  143. }
  144. }
  145. std::promise<MSVCPError> P;
  146. auto F = P.get_future();
  147. release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
  148. cantFail(F.get());
  149. }
  150. // SharedMemoryMapper
  151. SharedMemoryMapper::SharedMemoryMapper(ExecutorProcessControl &EPC,
  152. SymbolAddrs SAs, size_t PageSize)
  153. : EPC(EPC), SAs(SAs), PageSize(PageSize) {
  154. #if (!defined(LLVM_ON_UNIX) || defined(__ANDROID__)) && !defined(_WIN32)
  155. llvm_unreachable("SharedMemoryMapper is not supported on this platform yet");
  156. #endif
  157. }
  158. Expected<std::unique_ptr<SharedMemoryMapper>>
  159. SharedMemoryMapper::Create(ExecutorProcessControl &EPC, SymbolAddrs SAs) {
  160. #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
  161. auto PageSize = sys::Process::getPageSize();
  162. if (!PageSize)
  163. return PageSize.takeError();
  164. return std::make_unique<SharedMemoryMapper>(EPC, SAs, *PageSize);
  165. #else
  166. return make_error<StringError>(
  167. "SharedMemoryMapper is not supported on this platform yet",
  168. inconvertibleErrorCode());
  169. #endif
  170. }
  171. void SharedMemoryMapper::reserve(size_t NumBytes,
  172. OnReservedFunction OnReserved) {
  173. #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
  174. EPC.callSPSWrapperAsync<
  175. rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>(
  176. SAs.Reserve,
  177. [this, NumBytes, OnReserved = std::move(OnReserved)](
  178. Error SerializationErr,
  179. Expected<std::pair<ExecutorAddr, std::string>> Result) mutable {
  180. if (SerializationErr) {
  181. cantFail(Result.takeError());
  182. return OnReserved(std::move(SerializationErr));
  183. }
  184. if (!Result)
  185. return OnReserved(Result.takeError());
  186. ExecutorAddr RemoteAddr;
  187. std::string SharedMemoryName;
  188. std::tie(RemoteAddr, SharedMemoryName) = std::move(*Result);
  189. void *LocalAddr = nullptr;
  190. #if defined(LLVM_ON_UNIX)
  191. int SharedMemoryFile = shm_open(SharedMemoryName.c_str(), O_RDWR, 0700);
  192. if (SharedMemoryFile < 0) {
  193. return OnReserved(errorCodeToError(
  194. std::error_code(errno, std::generic_category())));
  195. }
  196. // this prevents other processes from accessing it by name
  197. shm_unlink(SharedMemoryName.c_str());
  198. LocalAddr = mmap(nullptr, NumBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
  199. SharedMemoryFile, 0);
  200. if (LocalAddr == MAP_FAILED) {
  201. return OnReserved(errorCodeToError(
  202. std::error_code(errno, std::generic_category())));
  203. }
  204. close(SharedMemoryFile);
  205. #elif defined(_WIN32)
  206. std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
  207. SharedMemoryName.end());
  208. HANDLE SharedMemoryFile = OpenFileMappingW(
  209. FILE_MAP_ALL_ACCESS, FALSE, WideSharedMemoryName.c_str());
  210. if (!SharedMemoryFile)
  211. return OnReserved(errorCodeToError(mapWindowsError(GetLastError())));
  212. LocalAddr =
  213. MapViewOfFile(SharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  214. if (!LocalAddr) {
  215. CloseHandle(SharedMemoryFile);
  216. return OnReserved(errorCodeToError(mapWindowsError(GetLastError())));
  217. }
  218. CloseHandle(SharedMemoryFile);
  219. #endif
  220. {
  221. std::lock_guard<std::mutex> Lock(Mutex);
  222. Reservations.insert({RemoteAddr, {LocalAddr, NumBytes}});
  223. }
  224. OnReserved(ExecutorAddrRange(RemoteAddr, NumBytes));
  225. },
  226. SAs.Instance, static_cast<uint64_t>(NumBytes));
  227. #else
  228. OnReserved(make_error<StringError>(
  229. "SharedMemoryMapper is not supported on this platform yet",
  230. inconvertibleErrorCode()));
  231. #endif
  232. }
  233. char *SharedMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) {
  234. auto R = Reservations.upper_bound(Addr);
  235. assert(R != Reservations.begin() && "Attempt to prepare unreserved range");
  236. R--;
  237. ExecutorAddrDiff Offset = Addr - R->first;
  238. return static_cast<char *>(R->second.LocalAddr) + Offset;
  239. }
  240. void SharedMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,
  241. OnInitializedFunction OnInitialized) {
  242. auto Reservation = Reservations.upper_bound(AI.MappingBase);
  243. assert(Reservation != Reservations.begin() && "Attempt to initialize unreserved range");
  244. Reservation--;
  245. auto AllocationOffset = AI.MappingBase - Reservation->first;
  246. tpctypes::SharedMemoryFinalizeRequest FR;
  247. AI.Actions.swap(FR.Actions);
  248. FR.Segments.reserve(AI.Segments.size());
  249. for (auto Segment : AI.Segments) {
  250. char *Base = static_cast<char *>(Reservation->second.LocalAddr) +
  251. AllocationOffset + Segment.Offset;
  252. std::memset(Base + Segment.ContentSize, 0, Segment.ZeroFillSize);
  253. tpctypes::SharedMemorySegFinalizeRequest SegReq;
  254. SegReq.AG = Segment.AG;
  255. SegReq.Addr = AI.MappingBase + Segment.Offset;
  256. SegReq.Size = Segment.ContentSize + Segment.ZeroFillSize;
  257. FR.Segments.push_back(SegReq);
  258. }
  259. EPC.callSPSWrapperAsync<
  260. rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>(
  261. SAs.Initialize,
  262. [OnInitialized = std::move(OnInitialized)](
  263. Error SerializationErr, Expected<ExecutorAddr> Result) mutable {
  264. if (SerializationErr) {
  265. cantFail(Result.takeError());
  266. return OnInitialized(std::move(SerializationErr));
  267. }
  268. OnInitialized(std::move(Result));
  269. },
  270. SAs.Instance, Reservation->first, std::move(FR));
  271. }
  272. void SharedMemoryMapper::deinitialize(
  273. ArrayRef<ExecutorAddr> Allocations,
  274. MemoryMapper::OnDeinitializedFunction OnDeinitialized) {
  275. EPC.callSPSWrapperAsync<
  276. rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>(
  277. SAs.Deinitialize,
  278. [OnDeinitialized = std::move(OnDeinitialized)](Error SerializationErr,
  279. Error Result) mutable {
  280. if (SerializationErr) {
  281. cantFail(std::move(Result));
  282. return OnDeinitialized(std::move(SerializationErr));
  283. }
  284. OnDeinitialized(std::move(Result));
  285. },
  286. SAs.Instance, Allocations);
  287. }
  288. void SharedMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,
  289. OnReleasedFunction OnReleased) {
  290. #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
  291. Error Err = Error::success();
  292. {
  293. std::lock_guard<std::mutex> Lock(Mutex);
  294. for (auto Base : Bases) {
  295. #if defined(LLVM_ON_UNIX)
  296. if (munmap(Reservations[Base].LocalAddr, Reservations[Base].Size) != 0)
  297. Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
  298. errno, std::generic_category())));
  299. #elif defined(_WIN32)
  300. if (!UnmapViewOfFile(Reservations[Base].LocalAddr))
  301. Err = joinErrors(std::move(Err),
  302. errorCodeToError(mapWindowsError(GetLastError())));
  303. #endif
  304. Reservations.erase(Base);
  305. }
  306. }
  307. EPC.callSPSWrapperAsync<
  308. rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>(
  309. SAs.Release,
  310. [OnReleased = std::move(OnReleased),
  311. Err = std::move(Err)](Error SerializationErr, Error Result) mutable {
  312. if (SerializationErr) {
  313. cantFail(std::move(Result));
  314. return OnReleased(
  315. joinErrors(std::move(Err), std::move(SerializationErr)));
  316. }
  317. return OnReleased(joinErrors(std::move(Err), std::move(Result)));
  318. },
  319. SAs.Instance, Bases);
  320. #else
  321. OnReleased(make_error<StringError>(
  322. "SharedMemoryMapper is not supported on this platform yet",
  323. inconvertibleErrorCode()));
  324. #endif
  325. }
  326. SharedMemoryMapper::~SharedMemoryMapper() {
  327. std::lock_guard<std::mutex> Lock(Mutex);
  328. for (const auto &R : Reservations) {
  329. #if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)
  330. munmap(R.second.LocalAddr, R.second.Size);
  331. #elif defined(_WIN32)
  332. UnmapViewOfFile(R.second.LocalAddr);
  333. #else
  334. (void)R;
  335. #endif
  336. }
  337. }
  338. } // namespace orc
  339. } // namespace llvm