CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/MemArenaPosix.cpp
Views: 1401
// Copyright (C) 2003 Dolphin Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official SVN repository and contact information can be found at15// http://code.google.com/p/dolphin-emu/1617#include "ppsspp_config.h"1819#if !defined(_WIN32) && !defined(ANDROID) && !defined(__APPLE__) && !PPSSPP_PLATFORM(SWITCH)2021#include <sys/mman.h>22#include <sys/stat.h>23#include <fcntl.h>24#include <unistd.h>25#include <cerrno>26#include <cstring>27#include <string>2829#ifndef MAP_NORESERVE30// Not implemented on BSDs31#define MAP_NORESERVE 032#endif3334#include "Common/Log.h"35#include "Common/File/FileUtil.h"36#include "Common/MemoryUtil.h"37#include "Common/MemArena.h"3839static const std::string tmpfs_location = "/dev/shm";40static const std::string tmpfs_ram_temp_file = "/dev/shm/gc_mem.tmp";4142// do not make this "static"43std::string ram_temp_file = "/tmp/gc_mem.tmp";4445size_t MemArena::roundup(size_t x) {46return x;47}4849bool MemArena::NeedsProbing() {50return false;51}5253bool MemArena::GrabMemSpace(size_t size) {54#ifndef NO_MMAP55constexpr mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;5657// Try a few times in case multiple instances are started near each other.58char ram_temp_filename[128]{};59bool is_shm = false;60for (int i = 0; i < 256; ++i) {61snprintf(ram_temp_filename, sizeof(ram_temp_filename), "/ppsspp_%d.ram", i);62// This opens atomically, so will fail if another process is starting.63fd = shm_open(ram_temp_filename, O_RDWR | O_CREAT | O_EXCL, mode);64if (fd >= 0) {65INFO_LOG(Log::MemMap, "Got shm file: %s", ram_temp_filename);66is_shm = true;67// Our handle persists per POSIX, so no need to keep it around.68if (shm_unlink(ram_temp_filename) != 0) {69WARN_LOG(Log::MemMap, "Failed to shm_unlink %s", ram_temp_file.c_str());70}71break;72}73}7475// Fall back to old tmpfs behavior.76if (fd < 0 && File::Exists(Path(tmpfs_location))) {77fd = open(tmpfs_ram_temp_file.c_str(), O_RDWR | O_CREAT, mode);78if (fd >= 0) {79// Great, this definitely shouldn't flush to disk.80ram_temp_file = tmpfs_ram_temp_file;81INFO_LOG(Log::MemMap, "Got tmpfs ram file: %s", tmpfs_ram_temp_file.c_str());82}83}8485if (fd < 0) {86INFO_LOG(Log::MemMap, "Trying '%s' as ram temp file", ram_temp_file.c_str());87fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode);88}89if (fd < 0) {90ERROR_LOG(Log::MemMap, "Failed to grab memory space as a file: %s of size: %08x. Error: %s", ram_temp_file.c_str(), (int)size, strerror(errno));91return false;92}93// delete immediately, we keep the fd so it still lives94if (!is_shm && unlink(ram_temp_file.c_str()) != 0) {95WARN_LOG(Log::MemMap, "Failed to unlink %s", ram_temp_file.c_str());96}97if (ftruncate(fd, size) != 0) {98ERROR_LOG(Log::MemMap, "Failed to ftruncate %d (%s) to size %08x", (int)fd, ram_temp_file.c_str(), (int)size);99// Should this be a failure?100}101#endif102return true;103}104105void MemArena::ReleaseSpace() {106#ifndef NO_MMAP107close(fd);108#endif109}110111void *MemArena::CreateView(s64 offset, size_t size, void *base)112{113#ifdef NO_MMAP114return (void*) base;115#else116void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED |117// Do not sync memory to underlying file. Linux has this by default.118#if defined(__DragonFly__) || defined(__FreeBSD__)119MAP_NOSYNC |120#endif121((base == 0) ? 0 : MAP_FIXED), fd, offset);122123if (retval == MAP_FAILED) {124NOTICE_LOG(Log::MemMap, "mmap on %s (fd: %d) failed: %s", ram_temp_file.c_str(), (int)fd, strerror(errno));125return 0;126}127return retval;128#endif129}130131void MemArena::ReleaseView(s64 offset, void* view, size_t size) {132#ifndef NO_MMAP133munmap(view, size);134#endif135}136137u8* MemArena::Find4GBBase() {138// Now, create views in high memory where there's plenty of space.139#if PPSSPP_ARCH(64BIT) && !defined(USE_ASAN) && !defined(NO_MMAP)140// We should probably just go look in /proc/self/maps for some free space.141// But let's try the anonymous mmap trick, just like on 32-bit, but bigger and142// aligned to 4GB for the movk trick. We can ensure that we get an aligned 4GB143// address by grabbing 8GB and aligning the pointer.144const uint64_t EIGHT_GIGS = 0x200000000ULL;145void *base = mmap(0, EIGHT_GIGS, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, -1, 0);146if (base && base != MAP_FAILED) {147INFO_LOG(Log::MemMap, "base: %p", base);148uint64_t aligned_base = ((uint64_t)base + 0xFFFFFFFF) & ~0xFFFFFFFFULL;149INFO_LOG(Log::MemMap, "aligned_base: %p", (void *)aligned_base);150munmap(base, EIGHT_GIGS);151return reinterpret_cast<u8 *>(aligned_base);152} else {153u8 *hardcoded_ptr = reinterpret_cast<u8*>(0x2300000000ULL);154INFO_LOG(Log::MemMap, "Failed to anonymously map 8GB (%s). Fall back to the hardcoded pointer %p.", strerror(errno), hardcoded_ptr);155// Just grab some random 4GB...156// This has been known to fail lately though, see issue #12249.157return hardcoded_ptr;158}159#elif defined(NO_MMAP)160void* base = std::malloc(0x0A000000);161return static_cast<u8*>(base);162#else163size_t size = 0x10000000;164void* base = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED | MAP_NORESERVE, -1, 0);165_assert_msg_(base != MAP_FAILED, "Failed to map 256 MB of memory space: %s", strerror(errno));166munmap(base, size);167return static_cast<u8*>(base);168#endif169}170171#endif172173174