diff options
Diffstat (limited to 'src/common/host_memory.cpp')
| -rw-r--r-- | src/common/host_memory.cpp | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 611c7d1a3..ba22595e0 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -11,9 +11,14 @@ | |||
| 11 | 11 | ||
| 12 | #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv | 12 | #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv |
| 13 | 13 | ||
| 14 | #ifdef ANDROID | ||
| 15 | #include <android/sharedmem.h> | ||
| 16 | #endif | ||
| 17 | |||
| 14 | #ifndef _GNU_SOURCE | 18 | #ifndef _GNU_SOURCE |
| 15 | #define _GNU_SOURCE | 19 | #define _GNU_SOURCE |
| 16 | #endif | 20 | #endif |
| 21 | #include <boost/icl/interval_set.hpp> | ||
| 17 | #include <fcntl.h> | 22 | #include <fcntl.h> |
| 18 | #include <sys/mman.h> | 23 | #include <sys/mman.h> |
| 19 | #include <unistd.h> | 24 | #include <unistd.h> |
| @@ -322,7 +327,7 @@ private: | |||
| 322 | } | 327 | } |
| 323 | 328 | ||
| 324 | /// Return true when a given memory region is a "nieche" and the placeholders don't have to be | 329 | /// Return true when a given memory region is a "nieche" and the placeholders don't have to be |
| 325 | /// splitted. | 330 | /// split. |
| 326 | bool IsNiechePlaceholder(size_t virtual_offset, size_t length) const { | 331 | bool IsNiechePlaceholder(size_t virtual_offset, size_t length) const { |
| 327 | const auto it = placeholders.upper_bound({virtual_offset, virtual_offset + length}); | 332 | const auto it = placeholders.upper_bound({virtual_offset, virtual_offset + length}); |
| 328 | if (it != placeholders.end() && it->lower() == virtual_offset + length) { | 333 | if (it != placeholders.end() && it->lower() == virtual_offset + length) { |
| @@ -366,17 +371,20 @@ public: | |||
| 366 | } | 371 | } |
| 367 | 372 | ||
| 368 | // Backing memory initialization | 373 | // Backing memory initialization |
| 369 | #if defined(__FreeBSD__) && __FreeBSD__ < 13 | 374 | #ifdef ANDROID |
| 375 | fd = ASharedMemory_create("HostMemory", backing_size); | ||
| 376 | #elif defined(__FreeBSD__) && __FreeBSD__ < 13 | ||
| 370 | // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 | 377 | // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 |
| 371 | fd = shm_open(SHM_ANON, O_RDWR, 0600); | 378 | fd = shm_open(SHM_ANON, O_RDWR, 0600); |
| 372 | #else | 379 | #else |
| 373 | fd = memfd_create("HostMemory", 0); | 380 | fd = memfd_create("HostMemory", 0); |
| 374 | #endif | 381 | #endif |
| 375 | if (fd == -1) { | 382 | if (fd < 0) { |
| 376 | LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); | 383 | LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); |
| 377 | throw std::bad_alloc{}; | 384 | throw std::bad_alloc{}; |
| 378 | } | 385 | } |
| 379 | 386 | ||
| 387 | #ifndef ANDROID | ||
| 380 | // Defined to extend the file with zeros | 388 | // Defined to extend the file with zeros |
| 381 | int ret = ftruncate(fd, backing_size); | 389 | int ret = ftruncate(fd, backing_size); |
| 382 | if (ret != 0) { | 390 | if (ret != 0) { |
| @@ -384,6 +392,7 @@ public: | |||
| 384 | strerror(errno)); | 392 | strerror(errno)); |
| 385 | throw std::bad_alloc{}; | 393 | throw std::bad_alloc{}; |
| 386 | } | 394 | } |
| 395 | #endif | ||
| 387 | 396 | ||
| 388 | backing_base = static_cast<u8*>( | 397 | backing_base = static_cast<u8*>( |
| 389 | mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); | 398 | mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); |
| @@ -415,6 +424,7 @@ public: | |||
| 415 | madvise(virtual_base, virtual_size, MADV_HUGEPAGE); | 424 | madvise(virtual_base, virtual_size, MADV_HUGEPAGE); |
| 416 | #endif | 425 | #endif |
| 417 | 426 | ||
| 427 | placeholders.add({0, virtual_size}); | ||
| 418 | good = true; | 428 | good = true; |
| 419 | } | 429 | } |
| 420 | 430 | ||
| @@ -423,6 +433,10 @@ public: | |||
| 423 | } | 433 | } |
| 424 | 434 | ||
| 425 | void Map(size_t virtual_offset, size_t host_offset, size_t length) { | 435 | void Map(size_t virtual_offset, size_t host_offset, size_t length) { |
| 436 | { | ||
| 437 | std::scoped_lock lock{placeholder_mutex}; | ||
| 438 | placeholders.subtract({virtual_offset, virtual_offset + length}); | ||
| 439 | } | ||
| 426 | 440 | ||
| 427 | void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE, | 441 | void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE, |
| 428 | MAP_SHARED | MAP_FIXED, fd, host_offset); | 442 | MAP_SHARED | MAP_FIXED, fd, host_offset); |
| @@ -433,6 +447,19 @@ public: | |||
| 433 | // The method name is wrong. We're still talking about the virtual range. | 447 | // The method name is wrong. We're still talking about the virtual range. |
| 434 | // We don't want to unmap, we want to reserve this memory. | 448 | // We don't want to unmap, we want to reserve this memory. |
| 435 | 449 | ||
| 450 | { | ||
| 451 | std::scoped_lock lock{placeholder_mutex}; | ||
| 452 | auto it = placeholders.find({virtual_offset - 1, virtual_offset + length + 1}); | ||
| 453 | |||
| 454 | if (it != placeholders.end()) { | ||
| 455 | size_t prev_upper = virtual_offset + length; | ||
| 456 | virtual_offset = std::min(virtual_offset, it->lower()); | ||
| 457 | length = std::max(it->upper(), prev_upper) - virtual_offset; | ||
| 458 | } | ||
| 459 | |||
| 460 | placeholders.add({virtual_offset, virtual_offset + length}); | ||
| 461 | } | ||
| 462 | |||
| 436 | void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE, | 463 | void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE, |
| 437 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); | 464 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); |
| 438 | ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); | 465 | ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); |
| @@ -476,6 +503,9 @@ private: | |||
| 476 | } | 503 | } |
| 477 | 504 | ||
| 478 | int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create | 505 | int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create |
| 506 | |||
| 507 | boost::icl::interval_set<size_t> placeholders; ///< Mapped placeholders | ||
| 508 | std::mutex placeholder_mutex; ///< Mutex for placeholders | ||
| 479 | }; | 509 | }; |
| 480 | 510 | ||
| 481 | #else // ^^^ Linux ^^^ vvv Generic vvv | 511 | #else // ^^^ Linux ^^^ vvv Generic vvv |
| @@ -484,7 +514,7 @@ class HostMemory::Impl { | |||
| 484 | public: | 514 | public: |
| 485 | explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) { | 515 | explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) { |
| 486 | // This is just a place holder. | 516 | // This is just a place holder. |
| 487 | // Please implement fastmem in a propper way on your platform. | 517 | // Please implement fastmem in a proper way on your platform. |
| 488 | throw std::bad_alloc{}; | 518 | throw std::bad_alloc{}; |
| 489 | } | 519 | } |
| 490 | 520 | ||