diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index ecc3ccf31e..48f4128eda 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -137,23 +137,23 @@ union spu_channel_t u32 value; }; - atomic_t sync_var; // atomic variable + atomic_t sync_var; public: bool try_push(u32 value) { - bool out_result; - - sync_var.atomic_op([&out_result, value](sync_var_t& data) + return sync_var.atomic_op([=](sync_var_t& data) -> bool { - if ((out_result = data.count == 0)) + if (data.count == 0) { data.count = 1; data.value = value; - } - }); - return out_result; + return true; + } + + return false; + }); } void push_bit_or(u32 value) @@ -168,33 +168,31 @@ public: bool try_pop(u32& out_value) { - bool out_result; - - sync_var.atomic_op([&out_result, &out_value](sync_var_t& data) + return sync_var.atomic_op([&](sync_var_t& data) -> bool { - if ((out_result = data.count != 0)) + if (data.count != 0) { out_value = data.value; + data.count = 0; data.value = 0; - } - }); - return out_result; + return true; + } + + return false; + }); } u32 pop_uncond() { - u32 out_value; - - sync_var.atomic_op([&out_value](sync_var_t& data) + return sync_var.atomic_op([](sync_var_t& data) -> u32 { - out_value = data.value; data.count = 0; - // value is not cleared and may be read again - }); - return out_value; + // value is not cleared and may be read again + return data.value; + }); } void set_value(u32 value, u32 count = 1) diff --git a/rpcs3/Emu/Memory/MemoryBlock.h b/rpcs3/Emu/Memory/MemoryBlock.h index e34d983a05..75a1cc8b52 100644 --- a/rpcs3/Emu/Memory/MemoryBlock.h +++ b/rpcs3/Emu/Memory/MemoryBlock.h @@ -46,6 +46,7 @@ public: VirtualMemoryBlock() = default; VirtualMemoryBlock* SetRange(const u32 start, const u32 size); + void Clear() { m_mapped_memory.clear(); m_reserve_size = 0; m_range_start = 0; m_range_size = 0; } u32 GetStartAddr() const { return m_range_start; } u32 GetSize() const { return m_range_size; } bool IsInMyRange(const u32 addr, const u32 size); diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 69205ed2a7..2aa3a316d6 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -85,9 +85,7 @@ namespace vm std::mutex m_mutex; public: - reservation_mutex_t() - { - } + reservation_mutex_t() = default; bool do_notify; @@ -130,10 +128,9 @@ namespace vm m_cv.notify_one(); } } - }; - const thread_ctrl_t* g_reservation_owner = nullptr; + const thread_ctrl_t* volatile g_reservation_owner = nullptr; u32 g_reservation_addr = 0; u32 g_reservation_size = 0; @@ -167,9 +164,9 @@ namespace vm throw EXCEPTION("System failure (addr=0x%x)", addr); } - g_reservation_owner = nullptr; g_reservation_addr = 0; g_reservation_size = 0; + g_reservation_owner = nullptr; } } @@ -270,9 +267,16 @@ namespace vm return true; } + bool reservation_test() + { + const auto owner = g_reservation_owner; + + return owner && owner == get_current_thread_ctrl(); + } + void reservation_free() { - if (g_reservation_owner && g_reservation_owner == get_current_thread_ctrl()) + if (reservation_test()) { std::lock_guard lock(g_reservation_mutex); @@ -404,10 +408,8 @@ namespace vm return true; } - void page_unmap(u32 addr, u32 size) + void _page_unmap(u32 addr, u32 size) { - std::lock_guard lock(g_reservation_mutex); - assert(size && (size | addr) % 4096 == 0); for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++) @@ -544,11 +546,13 @@ namespace vm block_t::~block_t() { + std::lock_guard lock(g_reservation_mutex); + // deallocate all memory for (auto& entry : m_map) { // unmap memory pages - vm::page_unmap(entry.first, entry.second); + vm::_page_unmap(entry.first, entry.second); } } @@ -568,7 +572,7 @@ namespace vm // return if size is invalid if (!size || size > this->size) { - return false; + return 0; } // search for an appropriate place (unoptimized) @@ -578,9 +582,14 @@ namespace vm { return addr; } + + if (used.load() + size > this->size) + { + return 0; + } } - return false; + return 0; } u32 block_t::falloc(u32 addr, u32 size) @@ -593,12 +602,12 @@ namespace vm // return if addr or size is invalid if (!size || size > this->size || addr < this->addr || addr + size - 1 >= this->addr + this->size - 1) { - return false; + return 0; } if (!try_alloc(addr, size)) { - return false; + return 0; } return addr; @@ -614,28 +623,28 @@ namespace vm { const u32 size = found->second; - // unmap memory pages - vm::page_unmap(addr, size); - // remove entry m_map.erase(found); // return "physical" memory used -= size; + // unmap memory pages + std::lock_guard{ g_reservation_mutex }, vm::_page_unmap(addr, size); + return true; } return false; } - std::shared_ptr map(u32 addr, u32 size, u32 flags) + std::shared_ptr map(u32 addr, u32 size, u64 flags) { std::lock_guard lock(g_reservation_mutex); - if (!size || (size | addr) % 4096 || flags) + if (!size || (size | addr) % 4096) { - throw EXCEPTION("Invalid arguments (addr=0x%x, size=0x%x, flags=0x%x)", addr, size, flags); + throw EXCEPTION("Invalid arguments (addr=0x%x, size=0x%x)", addr, size); } for (auto& block : g_locations) @@ -659,7 +668,7 @@ namespace vm } } - auto block = std::make_shared(addr, size); + auto block = std::make_shared(addr, size, flags); g_locations.emplace_back(block); diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 6c92b6ed17..e5bbe1a724 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -44,6 +44,9 @@ namespace vm // Process a memory access error if it's caused by the reservation bool reservation_query(u32 addr, u32 size, bool is_writing, std::function callback); + // Returns true if the current thread owns reservation + bool reservation_test(); + // Break all reservations created by the current thread void reservation_free(); @@ -66,7 +69,8 @@ namespace vm // Unmap memory at specified address (in optionally specified memory location) bool dealloc(u32 addr, memory_location_t location = any); - class block_t + // Object that handles memory allocations inside specific constant bounds ("location"), currently non-virtual + class block_t final { std::map m_map; // addr -> size mapping of mapped locations std::mutex m_mutex; @@ -76,9 +80,10 @@ namespace vm public: block_t() = delete; - block_t(u32 addr, u32 size) + block_t(u32 addr, u32 size, u64 flags = 0) : addr(addr) , size(size) + , flags(flags) { } @@ -87,6 +92,7 @@ namespace vm public: const u32 addr; // start address const u32 size; // total size + const u64 flags; // currently unused atomic_t used{}; // amount of memory used, may be increased manually prevent some memory from allocating @@ -101,7 +107,7 @@ namespace vm }; // create new memory block with specified parameters and return it - std::shared_ptr map(u32 addr, u32 size, u32 flags); + std::shared_ptr map(u32 addr, u32 size, u64 flags = 0); // delete existing memory block with specified start address std::shared_ptr unmap(u32 addr); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFiber.cpp b/rpcs3/Emu/SysCalls/Modules/cellFiber.cpp index 6336a1949b..df34569896 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFiber.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellFiber.cpp @@ -307,7 +307,7 @@ Module cellFiber("cellFiber", []() REG_FUNC_NR(cellFiber, cellFiberPpuExit); REG_FUNC_NR(cellFiber, cellFiberPpuYield); REG_FUNC_NR(cellFiber, cellFiberPpuJoinFiber); - REG_FUNC_NR(cellFiber, cellFiberPpuSelf); + REG_FUNC(cellFiber, cellFiberPpuSelf); REG_FUNC_NR(cellFiber, cellFiberPpuSendSignal); REG_FUNC_NR(cellFiber, cellFiberPpuWaitSignal); REG_FUNC_NR(cellFiber, cellFiberPpuWaitFlag); diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index 9221b4cdb1..68039113f0 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -324,15 +324,17 @@ s32 cellSurMixerCreate(vm::cptr config) libmixer.Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); - auto ppu = Emu.GetIdManager().make_ptr("Surmixer Thread"); + const auto ppu = Emu.GetIdManager().make_ptr("Surmixer Thread"); ppu->prio = 1001; ppu->stack_size = 0x10000; - ppu->custom_task = [](PPUThread& CPU) + ppu->custom_task = [](PPUThread& ppu) { AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; - while (port.state.load() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped()) + while (port.state.load() != AUDIO_PORT_STATE_CLOSED) { + CHECK_EMU_STATUS; + if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack @@ -346,7 +348,7 @@ s32 cellSurMixerCreate(vm::cptr config) memset(mixdata, 0, sizeof(mixdata)); if (surMixerCb) { - surMixerCb(CPU, surMixerCbArg, (u32)mixcount, 256); + surMixerCb(ppu, surMixerCbArg, (u32)mixcount, 256); } //u64 stamp1 = get_system_time(); @@ -453,14 +455,12 @@ s32 cellSurMixerCreate(vm::cptr config) surMixerCb.set(0); - const u32 id = CPU.GetId(); - - CallAfter([id]() - { - Emu.GetIdManager().remove(id); - }); + Emu.GetIdManager().remove(ppu.GetId()); }; + ppu->Run(); + ppu->Exec(); + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index 142bfcc88c..a5719bfca1 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -18,7 +18,7 @@ s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr(mutex_id)); + const auto mutex = Emu.GetIdManager().get(mutex_id); if (!mutex) { @@ -211,7 +211,7 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout) // reown the mutex (could be set when notified) if (!cond->mutex->owner) { - cond->mutex->owner = std::move(ppu.shared_from_this()); + cond->mutex->owner = ppu.shared_from_this(); } if (cond->mutex->owner.get() != &ppu) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp b/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp index 26bd98aa73..f934728865 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp @@ -49,27 +49,10 @@ s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr alloc_addr) } } - // Available memory reserved for containers - u32 available = 0; - - // Check all containers - for (auto& ct : Emu.GetIdManager().get_all()) - { - available += ct->size - ct->used; - } - - const auto area = vm::get(vm::user_space); - - // Check available memory - if (area->size < area->used.load() + available + size) - { - return CELL_ENOMEM; - } - // Allocate memory const u32 addr = - flags == SYS_MEMORY_PAGE_SIZE_1M ? area->alloc(size, 0x100000) : - flags == SYS_MEMORY_PAGE_SIZE_64K ? area->alloc(size, 0x10000) : + flags == SYS_MEMORY_PAGE_SIZE_1M ? vm::alloc(size, vm::user_space, 0x100000) : + flags == SYS_MEMORY_PAGE_SIZE_64K ? vm::alloc(size, vm::user_space, 0x10000) : throw EXCEPTION("Unexpected flags"); if (!addr) @@ -137,10 +120,15 @@ s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptrused -= size; + // Allocate memory const u32 addr = - flags == SYS_MEMORY_PAGE_SIZE_1M ? vm::alloc(size, vm::user_space, 0x100000) : - flags == SYS_MEMORY_PAGE_SIZE_64K ? vm::alloc(size, vm::user_space, 0x10000) : + flags == SYS_MEMORY_PAGE_SIZE_1M ? area->alloc(size, 0x100000) : + flags == SYS_MEMORY_PAGE_SIZE_64K ? area->alloc(size, 0x10000) : throw EXCEPTION("Unexpected flags"); if (!addr) @@ -164,6 +152,8 @@ s32 sys_memory_free(u32 addr) LV2_LOCK; + const auto area = vm::get(vm::user_space); + // Check all memory containers for (auto& ct : Emu.GetIdManager().get_all()) { @@ -171,20 +161,25 @@ s32 sys_memory_free(u32 addr) if (found != ct->allocs.end()) { - if (!vm::dealloc(addr, vm::user_space)) + const u32 size = found->second; + + if (!area->dealloc(addr)) { - throw EXCEPTION("Memory not deallocated (cid=0x%x, addr=0x%x, size=0x%x)", ct->id, addr, found->second); + throw EXCEPTION("Memory not deallocated (cid=0x%x, addr=0x%x, size=0x%x)", ct->id, addr, size); } - // Return memory size - ct->used -= found->second; + // Return memory + ct->used -= size; ct->allocs.erase(found); + // Fix "physical" memory + area->used += size; + return CELL_OK; } } - if (!vm::dealloc(addr, vm::user_space)) + if (!area->dealloc(addr)) { return CELL_EINVAL; } @@ -213,20 +208,18 @@ s32 sys_memory_get_user_memory_size(vm::ptr mem_info) LV2_LOCK; u32 reserved = 0; - u32 available = 0; // Check all memory containers for (auto& ct : Emu.GetIdManager().get_all()) { reserved += ct->size; - available += ct->size - ct->used; } const auto area = vm::get(vm::user_space); // Fetch the user memory available mem_info->total_user_memory = area->size - reserved; - mem_info->available_user_memory = area->size - area->used.load() - available; + mem_info->available_user_memory = area->size - area->used.load(); return CELL_OK; } @@ -246,19 +239,17 @@ s32 sys_memory_container_create(vm::ptr cid, u32 size) } u32 reserved = 0; - u32 available = 0; // Check all memory containers for (auto& ct : Emu.GetIdManager().get_all()) { reserved += ct->size; - available += ct->size - ct->used; } const auto area = vm::get(vm::user_space); if (area->size < reserved + size || - area->size - area->used.load() < available + size) + area->size - area->used.load() < size) { return CELL_ENOMEM; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp index 29f479479f..b262179256 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp @@ -42,7 +42,7 @@ s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr(alignment)) { - if (const auto area = vm::map(addr, static_cast(size), 0)) + if (const auto area = vm::map(addr, static_cast(size), flags)) { *alloc_addr = addr; @@ -63,7 +63,7 @@ s32 sys_mmapper_allocate_fixed_address() LV2_LOCK; - if (!vm::map(0xB0000000, 0x10000000, 0)) + if (!vm::map(0xB0000000, 0x10000000)) // TODO: set correct flags (they aren't used currently though) { return CELL_EEXIST; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp index d2908bfa76..9946e1a0af 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp @@ -76,7 +76,7 @@ s32 sys_mutex_destroy(u32 mutex_id) } // assuming that the mutex is locked immediately by another waiting thread when unlocked - if (!mutex->owner || !mutex->sq.empty()) + if (mutex->owner || mutex->sq.size()) { return CELL_EBUSY; } @@ -127,7 +127,7 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout) // lock immediately if not locked if (!mutex->owner) { - mutex->owner = std::move(ppu.shared_from_this()); + mutex->owner = ppu.shared_from_this(); return CELL_OK; } @@ -200,7 +200,7 @@ s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id) } // own the mutex if free - mutex->owner = std::move(ppu.shared_from_this()); + mutex->owner = ppu.shared_from_this(); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp index 5506df3ad3..666e9daed3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp @@ -31,12 +31,7 @@ void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode) if (!ppu.is_joinable) { - const u32 id = ppu.GetId(); - - CallAfter([id]() - { - Emu.GetIdManager().remove(id); - }); + Emu.GetIdManager().remove(ppu.GetId()); } ppu.Exit(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp b/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp index c1689797b6..c1ac82e38c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp @@ -19,7 +19,7 @@ s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::p const u32 new_addr = vm::check_addr(0x60000000) ? 0x70000000 : 0x60000000; // Map memory - const auto area = vm::map(new_addr, vsize, 0); + const auto area = vm::map(new_addr, vsize, flag); // Alloc memory if (!area || !area->alloc(vsize)) diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 69770cf81e..4d08f18be5 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -402,6 +402,7 @@ void Emulator::Stop() GetModuleManager().Close(); CurGameInfo.Reset(); + RSXIOMem.Clear(); vm::close(); finalize_ppu_exec_map();