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(); | ||||||
| 
 | 
 | ||||||
|  | @ -183,7 +199,7 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry | ||||||
| 
 | 
 | ||||||
|     // Wait until the thread is marked as running.
 |     // Wait until the thread is marked as running.
 | ||||||
|     wait_for_resumed(PASS_RDRAM thread_context); |     wait_for_resumed(PASS_RDRAM thread_context); | ||||||
|      | 
 | ||||||
|     // Make sure the thread wasn't replaced or destroyed before it was started.
 |     // Make sure the thread wasn't replaced or destroyed before it was started.
 | ||||||
|     if (self->context == thread_context) { |     if (self->context == thread_context) { | ||||||
|         debug_printf("[Thread] Thread started: %d\n", self->id); |         debug_printf("[Thread] Thread started: %d\n", self->id); | ||||||
|  | @ -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
	
	 Anghelo Carvajal
						Anghelo Carvajal