diff --git a/vita3k/app/src/app_init.cpp b/vita3k/app/src/app_init.cpp index 062442328..919d8ce85 100644 --- a/vita3k/app/src/app_init.cpp +++ b/vita3k/app/src/app_init.cpp @@ -443,7 +443,7 @@ void deinit(EmuEnvState &state) { state.net.abort_all(); state.http.shutdown_connections(); - state.kernel.exit_delete_all_threads_and_wait(); + state.kernel.process_exit(); state.motion.reset_runtime(); diff --git a/vita3k/display/src/display.cpp b/vita3k/display/src/display.cpp index 499d0db82..35383cd1f 100644 --- a/vita3k/display/src/display.cpp +++ b/vita3k/display/src/display.cpp @@ -104,13 +104,10 @@ void wait_vblank(DisplayState &display, KernelState &kernel, const ThreadStatePt } wait_thread->status_cond.wait(thread_lock, [&]() { - return wait_thread->status == ThreadStatus::run || kernel.shutting_down.load(std::memory_order_relaxed); + return wait_thread->status == ThreadStatus::run; }); } - if (kernel.shutting_down.load(std::memory_order_relaxed)) - return; - if (is_cb) { for (auto &[_, cb] : display.vblank_callbacks) { if (cb->get_owner_thread_id() == wait_thread->id) { diff --git a/vita3k/emuenv/include/emuenv/app_launch_request.h b/vita3k/emuenv/include/emuenv/app_launch_request.h new file mode 100644 index 000000000..1e23e3f2c --- /dev/null +++ b/vita3k/emuenv/include/emuenv/app_launch_request.h @@ -0,0 +1,34 @@ +// Vita3K emulator project +// Copyright (C) 2026 Vita3K team +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#pragma once + +#include +#include + +enum class AppLaunchReason { + User, + LoadExec, + ProcessExit, +}; + +struct AppLaunchRequest { + std::string app_path{}; + std::string self_path{}; + std::vector argv{}; + AppLaunchReason reason = AppLaunchReason::User; +}; diff --git a/vita3k/emuenv/include/emuenv/state.h b/vita3k/emuenv/include/emuenv/state.h index f77435eb3..f713a430b 100644 --- a/vita3k/emuenv/include/emuenv/state.h +++ b/vita3k/emuenv/include/emuenv/state.h @@ -81,17 +81,7 @@ typedef int SceUID; using NIDSet = std::set; -enum class AppLaunchReason { - User, - LoadExec -}; - -struct AppLaunchRequest { - std::string app_path{}; - std::string self_path{}; - std::vector argv{}; - AppLaunchReason reason = AppLaunchReason::User; -}; +#include /** * @brief State of the emulated PlayStation Vita environment diff --git a/vita3k/gui-qt/src/main_window.cpp b/vita3k/gui-qt/src/main_window.cpp index f4436cde2..899effbf5 100644 --- a/vita3k/gui-qt/src/main_window.cpp +++ b/vita3k/gui-qt/src/main_window.cpp @@ -811,7 +811,8 @@ bool MainWindow::handle_pending_app_launch_request() { return false; on_game_closed(); - boot_game(*request, false); + if (request->reason != AppLaunchReason::ProcessExit) + boot_game(*request, false); return true; } diff --git a/vita3k/interface.cpp b/vita3k/interface.cpp index 052670372..f5a848a89 100644 --- a/vita3k/interface.cpp +++ b/vita3k/interface.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -365,6 +366,9 @@ static ExitCode load_app_impl(SceUID &main_module_id, EmuEnvState &emuenv, const const auto call_import = [&emuenv](CPUState &cpu, uint32_t nid, SceUID thread_id) { ::call_import(emuenv, cpu, nid, thread_id); }; + emuenv.kernel.process_exit_callback = [&emuenv](int res, std::optional relaunch) { + emuenv.post_app_launch_request(relaunch.value_or(AppLaunchRequest{ .reason = AppLaunchReason::ProcessExit })); + }; if (!emuenv.kernel.init(emuenv.mem, call_import, emuenv.cfg.current_config.cpu_opt)) { LOG_WARN("Failed to init kernel!"); return KernelInitFailed; diff --git a/vita3k/kernel/CMakeLists.txt b/vita3k/kernel/CMakeLists.txt index 2932c5f91..9424ffc56 100644 --- a/vita3k/kernel/CMakeLists.txt +++ b/vita3k/kernel/CMakeLists.txt @@ -24,7 +24,7 @@ add_library( ${SOURCE_LIST} ) -target_include_directories(kernel PUBLIC include) +target_include_directories(kernel PUBLIC include ${CMAKE_CURRENT_SOURCE_DIR}/../emuenv/include) target_link_libraries(kernel PUBLIC rtc cpu mem util nids) target_link_libraries(kernel PRIVATE patch SDL3::SDL3 miniz vita-toolchain) if(TRACY_ENABLE_ON_CORE_COMPONENTS) diff --git a/vita3k/kernel/include/kernel/state.h b/vita3k/kernel/include/kernel/state.h index caf25d632..de27351eb 100644 --- a/vita3k/kernel/include/kernel/state.h +++ b/vita3k/kernel/include/kernel/state.h @@ -31,17 +31,19 @@ #include #include +#include + #include #include +#include #include #include +#include #include struct ThreadState; struct MemState; -struct SDL_Thread; - struct CodecEngineBlock; struct KernelModule { @@ -55,8 +57,6 @@ typedef std::shared_ptr ThreadStatePtr; typedef std::map CodecEngineBlocks; typedef std::map>> SlotToAddress; typedef std::map ThreadStatePtrs; -typedef std::shared_ptr ThreadPtr; -typedef std::map ThreadPtrs; typedef std::map SceKernelModuleInfoPtrs; typedef std::map CallbackPtrs; typedef unordered_map_fast ExportNids; @@ -157,13 +157,7 @@ struct KernelState { // kubridge exception handlers (DABT=0, PABT=1, UNDEF=2) static constexpr int EXCEPTION_HANDLER_MAX = 3; std::atomic
exception_handlers[EXCEPTION_HANDLER_MAX]{}; - std::mutex thread_lifecycle_mutex; - std::map host_threads; - std::mutex host_threads_mutex; - - std::atomic shutting_down{ false }; - std::mutex shutdown_mutex; - std::condition_variable shutdown_condvar; // for delay_thread + std::condition_variable thread_deleted_cond; SceUID get_next_uid() { return next_uid++; @@ -178,11 +172,17 @@ struct KernelState { ThreadStatePtr get_thread(SceUID thread_id); Ptr> get_thread_tls_addr(MemState &mem, SceUID thread_id, int key); - void exit_delete_all_threads_and_wait(); bool is_threads_paused() { return !paused_threads_status.empty(); } void pause_threads(); void resume_threads(); + // Kill all guest threads and block until they have exited. Must only be called from a host thread. + void process_exit(); + std::function)> process_exit_callback; + // Request process exit. Safe to call from a guest thread. Returns immediately. + // The registered process_exit_callback is invoked to notify the host layer. + void request_process_exit(int res, std::optional relaunch = std::nullopt); + void set_memory_watch(bool enabled); void invalidate_jit_cache(Address start, size_t length); SceKernelModuleInfo *find_module_by_addr(Address address); diff --git a/vita3k/kernel/include/kernel/thread/thread_state.h b/vita3k/kernel/include/kernel/thread/thread_state.h index 494bcc098..59095d77a 100644 --- a/vita3k/kernel/include/kernel/thread/thread_state.h +++ b/vita3k/kernel/include/kernel/thread/thread_state.h @@ -52,8 +52,6 @@ struct ThreadSignal { void wait(); bool send(); - std::atomic *shutting_down = nullptr; - private: std::mutex mutex; std::condition_variable recv_cond; diff --git a/vita3k/kernel/src/kernel.cpp b/vita3k/kernel/src/kernel.cpp index 13edcc02a..d36f8c376 100644 --- a/vita3k/kernel/src/kernel.cpp +++ b/vita3k/kernel/src/kernel.cpp @@ -74,9 +74,12 @@ static int SDLCALL thread_function(void *data) { thread->run_loop(); const uint32_t r0 = read_reg(*thread->cpu, 0); - std::lock_guard lock(params.kernel->mutex); - params.kernel->threads.erase(thread->id); - params.kernel->corenum_allocator.free_corenum(get_processor_id(*thread->cpu)); + { + std::lock_guard lock(params.kernel->mutex); + params.kernel->threads.erase(thread->id); + params.kernel->corenum_allocator.free_corenum(get_processor_id(*thread->cpu)); + params.kernel->thread_deleted_cond.notify_all(); + } return r0; } @@ -144,25 +147,12 @@ ThreadStatePtr KernelState::create_thread(MemState &mem, const char *name, Ptr entry_point, int init_priority, SceInt32 affinity_mask, int stack_size, const SceKernelThreadOptParam *option) { - if (shutting_down.load(std::memory_order_relaxed)) { - return nullptr; - } - ThreadStatePtr thread = std::make_shared(get_next_uid(), *this, mem); if (thread->init(name, entry_point, init_priority, affinity_mask, stack_size, option) < 0) return nullptr; - const auto release_corenum = [&]() { - corenum_allocator.free_corenum(get_processor_id(*thread->cpu)); - }; - - const std::lock_guard lifecycle_lock(thread_lifecycle_mutex); { const std::lock_guard lock(mutex); - if (shutting_down.load(std::memory_order_acquire)) { - release_corenum(); - return nullptr; - } threads.emplace(thread->id, thread); } @@ -171,15 +161,10 @@ ThreadStatePtr KernelState::create_thread(MemState &mem, const char *name, Ptrid; params.host_may_destroy_params = SDL_CreateSemaphore(0); - SDL_Thread *sdl_thread = SDL_CreateThread(&thread_function, thread->name.c_str(), ¶ms); + SDL_DetachThread(SDL_CreateThread(&thread_function, thread->name.c_str(), ¶ms)); SDL_WaitSemaphore(params.host_may_destroy_params); SDL_DestroySemaphore(params.host_may_destroy_params); - { - const std::lock_guard ht_lock(host_threads_mutex); - // TODO: lazy cleanup i forgor - host_threads.emplace(thread->id, sdl_thread); - } return thread; } @@ -195,55 +180,22 @@ Ptr> KernelState::get_thread_tls_addr(MemState &mem, SceUID thread_id, return address; } -void KernelState::exit_delete_all_threads_and_wait() { - { - const std::lock_guard lifecycle_lock(thread_lifecycle_mutex); - shutting_down.store(true, std::memory_order_release); - } +void KernelState::request_process_exit(int res, std::optional relaunch) { + if (process_exit_callback) + process_exit_callback(res, std::move(relaunch)); +} +void KernelState::process_exit() { { - const std::lock_guard lock(mutex); - for (auto &[_, timer] : timers) { + std::lock_guard lock(mutex); + for (auto &[_, timer] : timers) timer->condvar.notify_all(); - } - } - - shutdown_condvar.notify_all(); - - { - const std::lock_guard lock(mutex); for (auto &[_, thread] : threads) thread->exit_delete(false); } - std::map threads_to_join; - SDL_Thread *self_thread = nullptr; - SceUID self_thread_id = SCE_KERNEL_ERROR_ILLEGAL_THREAD_ID; - const SDL_ThreadID current_thread_id = SDL_GetCurrentThreadID(); - { - const std::lock_guard lock(host_threads_mutex); - threads_to_join.swap(host_threads); - } - - for (auto it = threads_to_join.begin(); it != threads_to_join.end(); ++it) { - if (SDL_GetThreadID(it->second) != current_thread_id) - continue; - - self_thread = it->second; - self_thread_id = it->first; - threads_to_join.erase(it); - break; - } - - if (self_thread) { - LOG_DEBUG("Detaching current host thread to avoid self-join (guest thread {}, host thread {})", self_thread_id, current_thread_id); - SDL_DetachThread(self_thread); - } - - LOG_DEBUG("Joining {} host threads", threads_to_join.size()); - for (auto &[id, sdl_thread] : threads_to_join) { - SDL_WaitThread(sdl_thread, nullptr); - } + std::unique_lock lock(mutex); + thread_deleted_cond.wait(lock, [this] { return threads.empty(); }); } void KernelState::pause_threads() { @@ -265,10 +217,7 @@ void KernelState::resume_threads() { } void KernelState::deinit(MemState &mem) { - { - const std::lock_guard lock(host_threads_mutex); - assert(host_threads.empty()); - } + process_exit(); threads.clear(); simple_events.clear(); @@ -323,8 +272,6 @@ void KernelState::deinit(MemState &mem) { next_uid = 1; - shutting_down.store(false, std::memory_order_relaxed); - paused_threads_status.clear(); } diff --git a/vita3k/kernel/src/sync_primitives.cpp b/vita3k/kernel/src/sync_primitives.cpp index 231bee85c..e8c48e6fc 100644 --- a/vita3k/kernel/src/sync_primitives.cpp +++ b/vita3k/kernel/src/sync_primitives.cpp @@ -81,17 +81,6 @@ inline static int handle_timeout(KernelState &kernel, const ThreadStatePtr &thre std::unique_lock &primitive_lock, WaitingThreadQueuePtr &queue, const ThreadDataQueueInterator &data_it, const char *export_name, SceUInt *const timeout) { - if (kernel.shutting_down.load(std::memory_order_relaxed)) { - thread_lock.lock(); - if (thread->status == ThreadStatus::wait) - thread->update_status(ThreadStatus::run); - thread_lock.unlock(); - auto found = queue->find(thread); - if (found != queue->end()) - queue->erase(found); - return SCE_KERNEL_ERROR_WAIT_CANCEL; - } - if (timeout) { bool status = false; auto start = std::chrono::steady_clock::now(); @@ -472,24 +461,22 @@ SceInt32 timer_waitorpoll(KernelState &kernel, const char *export_name, SceUID t const auto data_it = timer->waiting_threads->push(data); bool got_event = false; - while (!got_event && !kernel.shutting_down.load(std::memory_order_relaxed)) { + while (!got_event) { uint64_t wait_time = timer->next_event - current_time; // wait before we got an event and we are the first thread in the waiting list timer->condvar.wait_for(lock, std::chrono::microseconds(wait_time), [&] { - return kernel.shutting_down.load(std::memory_order_relaxed) + return thread->status == ThreadStatus::run || (*timer->waiting_threads->begin()).thread->id == thread_id; }); + if (thread->status == ThreadStatus::run) { + timer->waiting_threads->erase(data_it); + timer->condvar.notify_all(); + return SCE_KERNEL_ERROR_WAIT_CANCEL; + } current_time = get_current_time(); got_event = timer->event_set || current_time > timer->next_event; } - if (kernel.shutting_down.load(std::memory_order_relaxed)) { - timer->waiting_threads->erase(data_it); - thread->update_status(ThreadStatus::run, ThreadStatus::wait); - timer->condvar.notify_all(); - return SCE_KERNEL_ERROR_WAIT_CANCEL; - } - timer->waiting_threads->pop(); thread->update_status(ThreadStatus::run, ThreadStatus::wait); @@ -1766,12 +1753,8 @@ SceSize msgpipe_recv(KernelState &kernel, const char *export_name, SceUID thread // FIXME sleep on SimpleEvent msgpipe_lock.unlock(); // Unlock message pipe object, else we'll deadlock thread->status_cond.wait(thread_lock, [&] { - return thread->status == ThreadStatus::run || kernel.shutting_down.load(std::memory_order_relaxed); + return thread->status == ThreadStatus::run; }); - if (kernel.shutting_down.load(std::memory_order_relaxed)) { - thread->update_status(ThreadStatus::run); - return SCE_KERNEL_ERROR_WAIT_CANCEL; - } if (msgpipe->beingDeleted) { // if beingDeleted then message pipe is locked, so we can't lock again std::atomic_fetch_add(&msgpipe->remainingThreads, static_cast(-1)); return SCE_KERNEL_ERROR_WAIT_DELETE; @@ -1784,12 +1767,8 @@ SceSize msgpipe_recv(KernelState &kernel, const char *export_name, SceUID thread } else { // There's a timeout - wait until we can fill buffer or timeout msgpipe_lock.unlock(); // Unlock message pipe object, else we'll deadlock auto status = thread->status_cond.wait_for(thread_lock, std::chrono::microseconds{ *pTimeout }, [&] { - return thread->status == ThreadStatus::run || kernel.shutting_down.load(std::memory_order_relaxed); + return thread->status == ThreadStatus::run; }); - if (kernel.shutting_down.load(std::memory_order_relaxed)) { - thread->update_status(ThreadStatus::run); - return SCE_KERNEL_ERROR_WAIT_CANCEL; - } if (msgpipe->beingDeleted) { std::atomic_fetch_add(&msgpipe->remainingThreads, static_cast(-1)); return SCE_KERNEL_ERROR_WAIT_DELETE; @@ -1881,12 +1860,8 @@ SceSize msgpipe_send(KernelState &kernel, const char *export_name, SceUID thread // FIXME sleep on SimpleEvent msgpipe_lock.unlock(); // Unlock message pipe object, else we'll deadlock thread->status_cond.wait(thread_lock, [&] { - return thread->status == ThreadStatus::run || kernel.shutting_down.load(std::memory_order_relaxed); + return thread->status == ThreadStatus::run; }); - if (kernel.shutting_down.load(std::memory_order_relaxed)) { - thread->update_status(ThreadStatus::run); - return SCE_KERNEL_ERROR_WAIT_CANCEL; - } if (msgpipe->beingDeleted) { // if beingDeleted then message pipe is locked, so we can't lock again std::atomic_fetch_add(&msgpipe->remainingThreads, static_cast(-1)); return SCE_KERNEL_ERROR_WAIT_DELETE; @@ -1900,12 +1875,8 @@ SceSize msgpipe_send(KernelState &kernel, const char *export_name, SceUID thread } else { // There's a timeout - wait until we can fill buffer or timeout msgpipe_lock.unlock(); // Unlock message pipe object, else we'll deadlock auto status = thread->status_cond.wait_for(thread_lock, std::chrono::microseconds{ *pTimeout }, [&] { - return thread->status == ThreadStatus::run || kernel.shutting_down.load(std::memory_order_relaxed); + return thread->status == ThreadStatus::run; }); - if (kernel.shutting_down.load(std::memory_order_relaxed)) { - thread->update_status(ThreadStatus::run); - return SCE_KERNEL_ERROR_WAIT_CANCEL; - } if (msgpipe->beingDeleted) { std::atomic_fetch_add(&msgpipe->remainingThreads, static_cast(-1)); return SCE_KERNEL_ERROR_WAIT_DELETE; diff --git a/vita3k/kernel/src/thread.cpp b/vita3k/kernel/src/thread.cpp index dc2b55cf6..043bd1412 100644 --- a/vita3k/kernel/src/thread.cpp +++ b/vita3k/kernel/src/thread.cpp @@ -31,7 +31,7 @@ void ThreadSignal::wait() { std::unique_lock lock(mutex); - recv_cond.wait(lock, [&]() { return signaled || (shutting_down && shutting_down->load(std::memory_order_relaxed)); }); + recv_cond.wait(lock, [&]() { return signaled; }); signaled = false; } @@ -183,9 +183,8 @@ void ThreadState::exit_delete(bool exit) { stop(*cpu); } - // Wake if thread waiting on status_cond - if (status == ThreadStatus::wait) - update_status(ThreadStatus::run); + // Thread may enter a sync primitive wait after this runs, so always notify + update_status(ThreadStatus::run); // Wake if thread waiting on sceKernelWaitSignal signal.send(); @@ -426,12 +425,9 @@ uint32_t ThreadState::run_guest_function(Address callback_address, SceSize args, { // wait for the function to return std::unique_lock lock(mutex); - if (status != ThreadStatus::dormant || to_do == ThreadToDo::run) { - status_cond.wait(lock, [&]() { - return kernel.shutting_down.load(std::memory_order_relaxed) - || (status == ThreadStatus::dormant && to_do != ThreadToDo::run); - }); - } + status_cond.wait(lock, [&]() { + return status == ThreadStatus::dormant && to_do != ThreadToDo::run; + }); } entry_point = old_entry_point; @@ -442,13 +438,16 @@ ThreadState::ThreadState(SceUID id, KernelState &kernel, MemState &mem) : id(id) , kernel(kernel) , mem(mem) { - signal.shutting_down = &kernel.shutting_down; } void ThreadState::update_status(ThreadStatus status, std::optional expected) { if (expected) assert(expected.value() == this->status); + // Keep status as run after removal so handle_timeout's predicate is immediately satisfied + if (status == ThreadStatus::wait && to_do == ThreadToDo::remove) + return; + this->status = status; status_cond.notify_all(); diff --git a/vita3k/modules/SceAppMgr/SceAppMgr.cpp b/vita3k/modules/SceAppMgr/SceAppMgr.cpp index cc29beba9..88f8461c8 100644 --- a/vita3k/modules/SceAppMgr/SceAppMgr.cpp +++ b/vita3k/modules/SceAppMgr/SceAppMgr.cpp @@ -17,7 +17,6 @@ #include "SceAppMgr.h" -#include #include #include #include @@ -436,9 +435,7 @@ EXPORT(SceInt32, _sceAppMgrLoadExec, const char *appPath, Ptr const argv[] return RET_ERROR(SCE_APPMGR_ERROR_TOO_LONG_ARGV); } - emuenv.kernel.exit_delete_all_threads_and_wait(); - - app::request_in_process_launch(emuenv, { .app_path = emuenv.io.app_path, .self_path = std::move(exec_path), .argv = std::move(exec_argv), .reason = AppLaunchReason::LoadExec }); + emuenv.kernel.request_process_exit(0, AppLaunchRequest{ .app_path = emuenv.io.app_path, .self_path = std::move(exec_path), .argv = std::move(exec_argv), .reason = AppLaunchReason::LoadExec }); return SCE_KERNEL_OK; } diff --git a/vita3k/modules/SceKernelThreadMgr/SceThreadmgr.cpp b/vita3k/modules/SceKernelThreadMgr/SceThreadmgr.cpp index 4f1b95240..307facb26 100644 --- a/vita3k/modules/SceKernelThreadMgr/SceThreadmgr.cpp +++ b/vita3k/modules/SceKernelThreadMgr/SceThreadmgr.cpp @@ -849,10 +849,8 @@ static int wait_thread_end(KernelState &kernel, ThreadStatePtr &waiter, ThreadSt target->waiting_threads.push_back(waiter); } waiter->status_cond.wait(waiter_lock, [&]() { - return waiter->status == ThreadStatus::run || kernel.shutting_down.load(std::memory_order_relaxed); + return waiter->status == ThreadStatus::run; }); - if (kernel.shutting_down.load(std::memory_order_relaxed)) - return SCE_KERNEL_ERROR_WAIT_CANCEL; return 0; } @@ -1052,16 +1050,17 @@ EXPORT(int, sceKernelCreateThreadForUser, const char *name, SceKernelThreadEntry return thread->id; } -static int delay_thread(KernelState &kernel, SceUInt delay_us) { +static int delay_thread(KernelState &kernel, SceUID thread_id, SceUInt delay_us) { if (delay_us == 0) return SCE_KERNEL_ERROR_INVALID_ARGUMENT; - std::unique_lock lock(kernel.shutdown_mutex); - if (kernel.shutdown_condvar.wait_for(lock, std::chrono::microseconds(delay_us), - [&] { return kernel.shutting_down.load(std::memory_order_relaxed); })) { - return SCE_KERNEL_ERROR_WAIT_CANCEL; - } - + const ThreadStatePtr thread = kernel.get_thread(thread_id); + std::unique_lock lock(thread->mutex); + thread->update_status(ThreadStatus::wait); + thread->status_cond.wait_for(lock, std::chrono::microseconds(delay_us), + [&] { return thread->status == ThreadStatus::run; }); + if (thread->status != ThreadStatus::run) + thread->update_status(ThreadStatus::run); return SCE_KERNEL_OK; } @@ -1072,21 +1071,21 @@ static int delay_thread_cb(EmuEnvState &emuenv, SceUID thread_id, SceUInt delay_ auto elapsed = std::chrono::duration_cast(end - start); if (delay_us > elapsed.count()) // If we spent less time than requested processing callbacks, sleep the remaining time - return delay_thread(emuenv.kernel, delay_us - elapsed.count()); + return delay_thread(emuenv.kernel, thread_id, delay_us - elapsed.count()); else // Else return directly return SCE_KERNEL_OK; } EXPORT(int, sceKernelDelayThread, SceUInt delay) { TRACY_FUNC(sceKernelDelayThread, delay); - return delay_thread(emuenv.kernel, delay); + return delay_thread(emuenv.kernel, thread_id, delay); } EXPORT(int, sceKernelDelayThread200, SceUInt delay) { TRACY_FUNC(sceKernelDelayThread200, delay); if (delay < 201) delay = 201; - return delay_thread(emuenv.kernel, delay); + return delay_thread(emuenv.kernel, thread_id, delay); } EXPORT(int, sceKernelDelayThreadCB, SceUInt delay) { diff --git a/vita3k/modules/SceLibDbg/SceDbg.cpp b/vita3k/modules/SceLibDbg/SceDbg.cpp index e1e677e8c..a3178c86b 100644 --- a/vita3k/modules/SceLibDbg/SceDbg.cpp +++ b/vita3k/modules/SceLibDbg/SceDbg.cpp @@ -40,14 +40,12 @@ EXPORT(int, sceDbgAssertionHandler, const char *filename, int line, bool do_stop LOG_INFO("file {}, line {}, {}", filename, line, buffer.data()); if (do_stop) - emuenv.kernel.exit_delete_all_threads_and_wait(); + emuenv.kernel.request_process_exit(0); if (!result) { return SCE_KERNEL_ERROR_INVALID_ARGUMENT; } - assert(!do_stop); - return 0; } diff --git a/vita3k/modules/SceLibKernel/SceLibKernel.cpp b/vita3k/modules/SceLibKernel/SceLibKernel.cpp index c97b9b48a..7bcd61980 100644 --- a/vita3k/modules/SceLibKernel/SceLibKernel.cpp +++ b/vita3k/modules/SceLibKernel/SceLibKernel.cpp @@ -1290,9 +1290,7 @@ EXPORT(int, sceKernelDeleteLwMutex, Ptr workarea) { EXPORT(int, sceKernelExitProcess, int res) { TRACY_FUNC(sceKernelExitProcess, res); - // TODO Handle exit code? - emuenv.kernel.exit_delete_all_threads_and_wait(); - + emuenv.kernel.request_process_exit(res); return SCE_KERNEL_OK; }