mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2025-10-30 08:02:29 +00:00
Remove "permanent" and "temporary" threads tagging and add a way to name game threads (#45)
* System to specify thread types by the game * Register threads callbacks * Remove temporary and permanent threads * Fix `pthread_setname_np` not liking names longer than 16 bytes * Singular * Rename events_callbacks arg * Use `prctl` instead of `pthread_setname_np` for naming a thread * Fix typo
This commit is contained in:
parent
c91627740f
commit
27282afa2b
7 changed files with 76 additions and 43 deletions
|
|
@ -56,7 +56,8 @@ namespace recomp {
|
||||||
const ultramodern::input::callbacks_t& input_callbacks,
|
const ultramodern::input::callbacks_t& input_callbacks,
|
||||||
const ultramodern::gfx_callbacks_t& gfx_callbacks,
|
const ultramodern::gfx_callbacks_t& gfx_callbacks,
|
||||||
const ultramodern::events::callbacks_t& events_callbacks,
|
const ultramodern::events::callbacks_t& events_callbacks,
|
||||||
const ultramodern::error_handling::callbacks_t& error_handling_callbacks_
|
const ultramodern::error_handling::callbacks_t& error_handling_callbacks,
|
||||||
|
const ultramodern::threads::callbacks_t& threads_callbacks
|
||||||
);
|
);
|
||||||
|
|
||||||
void start_game(const std::u8string& game_id);
|
void start_game(const std::u8string& game_id);
|
||||||
|
|
|
||||||
|
|
@ -381,7 +381,8 @@ void recomp::start(
|
||||||
const ultramodern::input::callbacks_t& input_callbacks,
|
const ultramodern::input::callbacks_t& input_callbacks,
|
||||||
const ultramodern::gfx_callbacks_t& gfx_callbacks_,
|
const ultramodern::gfx_callbacks_t& gfx_callbacks_,
|
||||||
const ultramodern::events::callbacks_t& events_callbacks,
|
const ultramodern::events::callbacks_t& events_callbacks,
|
||||||
const ultramodern::error_handling::callbacks_t& error_handling_callbacks_
|
const ultramodern::error_handling::callbacks_t& error_handling_callbacks,
|
||||||
|
const ultramodern::threads::callbacks_t& threads_callbacks
|
||||||
) {
|
) {
|
||||||
recomp::check_all_stored_roms();
|
recomp::check_all_stored_roms();
|
||||||
|
|
||||||
|
|
@ -392,7 +393,7 @@ void recomp::start(
|
||||||
.run_task = recomp::rsp::run_task,
|
.run_task = recomp::rsp::run_task,
|
||||||
};
|
};
|
||||||
|
|
||||||
ultramodern::set_callbacks(ultramodern_rsp_callbacks, renderer_callbacks, audio_callbacks, input_callbacks, gfx_callbacks_, events_callbacks, error_handling_callbacks_);
|
ultramodern::set_callbacks(ultramodern_rsp_callbacks, renderer_callbacks, audio_callbacks, input_callbacks, gfx_callbacks_, events_callbacks, error_handling_callbacks, threads_callbacks);
|
||||||
|
|
||||||
ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
|
ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
#ifndef __RSP_STUFF_HPP__
|
#ifndef __RSP_HPP__
|
||||||
#define __RSP_STUFF_HPP__
|
#define __RSP_HPP__
|
||||||
|
|
||||||
// TODO: rename
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "ultra64.h"
|
#include "ultra64.h"
|
||||||
|
|
||||||
// TODO: Move these to ultramodern namespace?
|
|
||||||
|
|
||||||
namespace ultramodern {
|
namespace ultramodern {
|
||||||
namespace rsp {
|
namespace rsp {
|
||||||
struct callbacks_t {
|
struct callbacks_t {
|
||||||
|
|
|
||||||
29
ultramodern/include/ultramodern/threads.hpp
Normal file
29
ultramodern/include/ultramodern/threads.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef __THREADS_HPP__
|
||||||
|
#define __THREADS_HPP__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "ultra64.h"
|
||||||
|
|
||||||
|
namespace ultramodern {
|
||||||
|
namespace threads {
|
||||||
|
struct callbacks_t {
|
||||||
|
using get_game_thread_name_t = std::string(const OSThread* t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to specifying a custom name for each thread. Mainly for debugging purposes.
|
||||||
|
*
|
||||||
|
* For maximum cross-platform compatibility the returned name should be at most 15 bytes long (16 bytes including the null terminator).
|
||||||
|
*
|
||||||
|
* If this function is not provided then the thread id will be used as the name of the thread.
|
||||||
|
*/
|
||||||
|
get_game_thread_name_t *get_game_thread_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_callbacks(const callbacks_t& callbacks);
|
||||||
|
|
||||||
|
std::string get_game_thread_name(const OSThread* t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -9,13 +9,15 @@
|
||||||
#undef MOODYCAMEL_DELETE_FUNCTION
|
#undef MOODYCAMEL_DELETE_FUNCTION
|
||||||
#define MOODYCAMEL_DELETE_FUNCTION = delete
|
#define MOODYCAMEL_DELETE_FUNCTION = delete
|
||||||
#include "lightweightsemaphore.h"
|
#include "lightweightsemaphore.h"
|
||||||
|
|
||||||
#include "ultra64.h"
|
#include "ultra64.h"
|
||||||
|
|
||||||
#include "ultramodern/error_handling.hpp"
|
#include "ultramodern/error_handling.hpp"
|
||||||
#include "ultramodern/events.hpp"
|
#include "ultramodern/events.hpp"
|
||||||
#include "ultramodern/input.hpp"
|
#include "ultramodern/input.hpp"
|
||||||
#include "ultramodern/rsp.hpp"
|
|
||||||
#include "ultramodern/renderer_context.hpp"
|
#include "ultramodern/renderer_context.hpp"
|
||||||
|
#include "ultramodern/rsp.hpp"
|
||||||
|
#include "ultramodern/threads.hpp"
|
||||||
|
|
||||||
struct UltraThreadContext {
|
struct UltraThreadContext {
|
||||||
std::thread host_thread;
|
std::thread host_thread;
|
||||||
|
|
@ -58,8 +60,6 @@ void run_next_thread_and_wait(RDRAM_ARG1);
|
||||||
void resume_thread_and_wait(RDRAM_ARG OSThread* t);
|
void resume_thread_and_wait(RDRAM_ARG OSThread* t);
|
||||||
void schedule_running_thread(RDRAM_ARG PTR(OSThread) t);
|
void schedule_running_thread(RDRAM_ARG PTR(OSThread) t);
|
||||||
void cleanup_thread(UltraThreadContext* thread_context);
|
void cleanup_thread(UltraThreadContext* thread_context);
|
||||||
uint32_t permanent_thread_count();
|
|
||||||
uint32_t temporary_thread_count();
|
|
||||||
struct thread_terminated : std::exception {};
|
struct thread_terminated : std::exception {};
|
||||||
|
|
||||||
enum class ThreadPriority {
|
enum class ThreadPriority {
|
||||||
|
|
@ -144,7 +144,8 @@ void set_callbacks(
|
||||||
const input::callbacks_t& input_callbacks,
|
const input::callbacks_t& input_callbacks,
|
||||||
const gfx_callbacks_t& gfx_callbacks,
|
const gfx_callbacks_t& gfx_callbacks,
|
||||||
const events::callbacks_t& events_callbacks,
|
const events::callbacks_t& events_callbacks,
|
||||||
const error_handling::callbacks_t& error_handling_callbacks
|
const error_handling::callbacks_t& error_handling_callbacks,
|
||||||
|
const threads::callbacks_t& threads_callbacks
|
||||||
);
|
);
|
||||||
} // namespace ultramodern
|
} // namespace ultramodern
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,26 @@
|
||||||
#include "ultramodern/ultramodern.hpp"
|
#include "ultramodern/ultramodern.hpp"
|
||||||
#include "blockingconcurrentqueue.h"
|
#include "blockingconcurrentqueue.h"
|
||||||
|
|
||||||
|
#include "ultramodern/threads.hpp"
|
||||||
|
|
||||||
// Native APIs only used to set thread names for easier debugging
|
// Native APIs only used to set thread names for easier debugging
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static ultramodern::threads::callbacks_t threads_callbacks;
|
||||||
|
|
||||||
|
void ultramodern::threads::set_callbacks(const callbacks_t& callbacks) {
|
||||||
|
threads_callbacks = callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ultramodern::threads::get_game_thread_name(const OSThread* t) {
|
||||||
|
if (threads_callbacks.get_game_thread_name == nullptr) {
|
||||||
|
return "Game Thread " + std::to_string(t->id);
|
||||||
|
}
|
||||||
|
return threads_callbacks.get_game_thread_name(t);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void bootproc();
|
extern "C" void bootproc();
|
||||||
|
|
||||||
thread_local bool is_main_thread = false;
|
thread_local bool is_main_thread = false;
|
||||||
|
|
@ -80,8 +95,15 @@ void ultramodern::set_native_thread_priority(ThreadPriority pri) {
|
||||||
// SetThreadPriority(GetCurrentThread(), nPriority);
|
// SetThreadPriority(GetCurrentThread(), nPriority);
|
||||||
}
|
}
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
void ultramodern::set_native_thread_name(const std::string& name) {
|
void ultramodern::set_native_thread_name(const std::string& name) {
|
||||||
pthread_setname_np(pthread_self(), name.c_str());
|
if (name.length() > 15) {
|
||||||
|
// Linux only accepts up to 16 characters including the null terminator for a thread name.
|
||||||
|
debug_printf("[Thread] The thread name '%s' will be truncated to 15 characters", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
prctl(PR_SET_NAME, name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::set_native_thread_priority(ThreadPriority pri) {
|
void ultramodern::set_native_thread_priority(ThreadPriority pri) {
|
||||||
|
|
@ -113,15 +135,17 @@ void ultramodern::set_native_thread_priority(ThreadPriority pri) {
|
||||||
}
|
}
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
void ultramodern::set_native_thread_name(const std::string& name) {
|
void ultramodern::set_native_thread_name(const std::string& name) {
|
||||||
|
if (name.length() > 15) {
|
||||||
|
// Macs seem to only accept up to 16 characters including the null terminator for a thread name.
|
||||||
|
debug_printf("[Thread] The thread name '%s' will be truncated to 15 characters", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
pthread_setname_np(name.c_str());
|
pthread_setname_np(name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::set_native_thread_priority(ThreadPriority pri) {}
|
void ultramodern::set_native_thread_priority(ThreadPriority pri) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::atomic_int temporary_threads = 0;
|
|
||||||
std::atomic_int permanent_threads = 0;
|
|
||||||
|
|
||||||
void wait_for_resumed(RDRAM_ARG UltraThreadContext* thread_context) {
|
void wait_for_resumed(RDRAM_ARG UltraThreadContext* thread_context) {
|
||||||
TO_PTR(OSThread, ultramodern::this_thread())->context->running.wait();
|
TO_PTR(OSThread, ultramodern::this_thread())->context->running.wait();
|
||||||
// If this thread's context was replaced by another thread or deleted, destroy it again from its own context.
|
// If this thread's context was replaced by another thread or deleted, destroy it again from its own context.
|
||||||
|
|
@ -165,17 +189,9 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry
|
||||||
is_game_thread = true;
|
is_game_thread = true;
|
||||||
|
|
||||||
// Set the thread name
|
// Set the thread name
|
||||||
ultramodern::set_native_thread_name("Game Thread " + std::to_string(self->id));
|
ultramodern::set_native_thread_name(ultramodern::threads::get_game_thread_name(self));
|
||||||
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::High);
|
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::High);
|
||||||
|
|
||||||
// TODO fix these being hardcoded (this is only used for quicksaving)
|
|
||||||
if ((self->id == 2 && self->priority == 5) || self->id == 13) { // slowly, flashrom
|
|
||||||
temporary_threads.fetch_add(1);
|
|
||||||
}
|
|
||||||
else if (self->id != 1 && self->id != 2) { // ignore idle and fault
|
|
||||||
permanent_threads.fetch_add(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal the initialized semaphore to indicate that this thread can be started.
|
// Signal the initialized semaphore to indicate that this thread can be started.
|
||||||
thread_context->initialized.signal();
|
thread_context->initialized.signal();
|
||||||
|
|
||||||
|
|
@ -206,19 +222,6 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry
|
||||||
|
|
||||||
// Dispose of this thread now that it's completed or terminated.
|
// Dispose of this thread now that it's completed or terminated.
|
||||||
ultramodern::cleanup_thread(thread_context);
|
ultramodern::cleanup_thread(thread_context);
|
||||||
|
|
||||||
// TODO fix these being hardcoded (this is only used for quicksaving)
|
|
||||||
if ((self->id == 2 && self->priority == 5) || self->id == 13) { // slowly, flashrom
|
|
||||||
temporary_threads.fetch_sub(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ultramodern::permanent_thread_count() {
|
|
||||||
return permanent_threads.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ultramodern::temporary_thread_count() {
|
|
||||||
return temporary_threads.load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void osStartThread(RDRAM_ARG PTR(OSThread) t_) {
|
extern "C" void osStartThread(RDRAM_ARG PTR(OSThread) t_) {
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,18 @@ void ultramodern::set_callbacks(
|
||||||
const audio_callbacks_t& audio_callbacks,
|
const audio_callbacks_t& audio_callbacks,
|
||||||
const input::callbacks_t& input_callbacks,
|
const input::callbacks_t& input_callbacks,
|
||||||
const gfx_callbacks_t& gfx_callbacks,
|
const gfx_callbacks_t& gfx_callbacks,
|
||||||
const events::callbacks_t& thread_callbacks,
|
const events::callbacks_t& events_callbacks,
|
||||||
const error_handling::callbacks_t& error_handling_callbacks
|
const error_handling::callbacks_t& error_handling_callbacks,
|
||||||
|
const threads::callbacks_t& threads_callbacks
|
||||||
) {
|
) {
|
||||||
ultramodern::rsp::set_callbacks(rsp_callbacks);
|
ultramodern::rsp::set_callbacks(rsp_callbacks);
|
||||||
ultramodern::renderer::set_callbacks(renderer_callbacks);
|
ultramodern::renderer::set_callbacks(renderer_callbacks);
|
||||||
ultramodern::set_audio_callbacks(audio_callbacks);
|
ultramodern::set_audio_callbacks(audio_callbacks);
|
||||||
ultramodern::input::set_callbacks(input_callbacks);
|
ultramodern::input::set_callbacks(input_callbacks);
|
||||||
(void)gfx_callbacks; // nothing yet
|
(void)gfx_callbacks; // nothing yet
|
||||||
ultramodern::events::set_callbacks(thread_callbacks);
|
ultramodern::events::set_callbacks(events_callbacks);
|
||||||
ultramodern::error_handling::set_callbacks(error_handling_callbacks);
|
ultramodern::error_handling::set_callbacks(error_handling_callbacks);
|
||||||
|
ultramodern::threads::set_callbacks(threads_callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::preinit(RDRAM_ARG ultramodern::renderer::WindowHandle window_handle) {
|
void ultramodern::preinit(RDRAM_ARG ultramodern::renderer::WindowHandle window_handle) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue