diff --git a/src/xenia/core.h b/src/xenia/core.h index 2c6391931..75b7177af 100644 --- a/src/xenia/core.h +++ b/src/xenia/core.h @@ -18,5 +18,6 @@ #include #include #include +#include #endif // XENIA_CORE_H_ diff --git a/src/xenia/core/sources.gypi b/src/xenia/core/sources.gypi index 23e8340ad..884890b67 100644 --- a/src/xenia/core/sources.gypi +++ b/src/xenia/core/sources.gypi @@ -11,6 +11,8 @@ 'pal.h', 'ref.cc', 'ref.h', + 'thread.cc', + 'thread.h', ], 'conditions': [ diff --git a/src/xenia/core/thread.cc b/src/xenia/core/thread.cc new file mode 100644 index 000000000..16f3f895c --- /dev/null +++ b/src/xenia/core/thread.cc @@ -0,0 +1,137 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + + +typedef struct xe_thread { + xe_ref_t ref; + + char* name; + + xe_thread_callback callback; + void* callback_param; + + void* handle; +} xe_thread_t; + + + +xe_thread_ref xe_thread_create( + xe_pal_ref pal, const char* name, xe_thread_callback callback, + void* param) { + xe_thread_ref thread = (xe_thread_ref)xe_calloc(sizeof(xe_thread_t)); + xe_ref_init((xe_ref)thread); + + thread->name = xestrdupa(name); + thread->callback = callback; + thread->callback_param = param; + + return thread; +} + +void xe_thread_dealloc(xe_thread_ref thread) { + thread->handle = NULL; + xe_free(thread->name); +} + +xe_thread_ref xe_thread_retain(xe_thread_ref thread) { + xe_ref_retain((xe_ref)thread); + return thread; +} + +void xe_thread_release(xe_thread_ref thread) { + xe_ref_release((xe_ref)thread, (xe_ref_dealloc_t)xe_thread_dealloc); +} + +#if XE_PLATFORM(WIN32) + +// http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +#pragma warning(disable : 6320; disable : 6322) +static uint32_t __stdcall xe_thread_callback_win32(void* param) { + xe_thread_t* thread = reinterpret_cast(param); + + if (IsDebuggerPresent()) { + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = thread->name; + info.dwThreadID = (DWORD)-1; + info.dwFlags = 0; + __try { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), + (ULONG_PTR*)&info); + } __except(EXCEPTION_EXECUTE_HANDLER) { + } + } + + thread->callback(thread->callback_param); + return 0; +} +#pragma warning(default : 6320; default : 6322) + +int xe_thread_start(xe_thread_ref thread) { + HANDLE thread_handle = CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)xe_thread_callback_win32, + thread, + 0, + NULL); + if (!handle) { + uint32_t last_error = GetLastError(); + // TODO(benvanik): translate? + XELOGE(XT("CreateThread failed with %d"), last_error); + return last_error; + } + + thread->handle = reinterpret_cast(thread_handle); + + return 0; +} + +#else + +static void* xe_thread_callback_pthreads(void* param) { + xe_thread_t* thread = reinterpret_cast(param); + XEIGNORE(pthread_setname_np(thread->name)); + thread->callback(thread->callback_param); + return 0; +} + +int xe_thread_start(xe_thread_ref thread) { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_t thread_handle; + int result_code = pthread_create( + &thread_handle, + &attr, + &xe_thread_callback_pthreads, + thread); + pthread_attr_destroy(&attr); + if (result_code) { + return result_code; + } + + thread->handle = reinterpret_cast(thread_handle); + + return 0; +} + +#endif // WIN32 diff --git a/src/xenia/core/thread.h b/src/xenia/core/thread.h new file mode 100644 index 000000000..4c707d9c8 --- /dev/null +++ b/src/xenia/core/thread.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_CORE_THREAD_H_ +#define XENIA_CORE_THREAD_H_ + +#include +#include +#include + + +struct xe_thread; +typedef struct xe_thread* xe_thread_ref; + + +typedef void (*xe_thread_callback)(void* param); + + +xe_thread_ref xe_thread_create( + xe_pal_ref pal, const char* name, xe_thread_callback callback, void* param); +xe_thread_ref xe_thread_retain(xe_thread_ref thread); +void xe_thread_release(xe_thread_ref thread); + +int xe_thread_start(xe_thread_ref thread); + + +#endif // XENIA_CORE_THREAD_H_ diff --git a/src/xenia/dbg/debugger.cc b/src/xenia/dbg/debugger.cc index 0080035a8..c0d89cf8b 100644 --- a/src/xenia/dbg/debugger.cc +++ b/src/xenia/dbg/debugger.cc @@ -48,6 +48,10 @@ Debugger::~Debugger() { xe_pal_release(pal_); } +xe_pal_ref Debugger::pal() { + return xe_pal_retain(pal_); +} + void Debugger::RegisterContentSource(ContentSource* content_source) { content_sources_.insert(std::pair( content_source->source_id(), content_source)); diff --git a/src/xenia/dbg/debugger.h b/src/xenia/dbg/debugger.h index dbe7da236..71453334d 100644 --- a/src/xenia/dbg/debugger.h +++ b/src/xenia/dbg/debugger.h @@ -31,6 +31,8 @@ public: Debugger(xe_pal_ref pal); virtual ~Debugger(); + xe_pal_ref pal(); + void RegisterContentSource(ContentSource* content_source); int Startup(); diff --git a/src/xenia/dbg/ws_client.cc b/src/xenia/dbg/ws_client.cc index 4f3b12a32..3f399051b 100644 --- a/src/xenia/dbg/ws_client.cc +++ b/src/xenia/dbg/ws_client.cc @@ -30,6 +30,7 @@ using namespace xe::dbg; WsClient::WsClient(Debugger* debugger, int socket_id) : Client(debugger), + thread_(NULL), socket_id_(socket_id) { mutex_ = xe_mutex_alloc(1000); @@ -49,6 +50,8 @@ WsClient::~WsClient() { xe_mutex_unlock(mutex); xe_mutex_free(mutex); + xe_thread_release(thread_); + close(notify_rd_id_); close(notify_wr_id_); } @@ -67,25 +70,16 @@ int WsClient::Setup() { setsockopt(socket_id_, IPPROTO_TCP, TCP_NODELAY, &opt_value, sizeof(opt_value)); - // TODO(benvanik): win32 support - put simple threads in PAL - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_t thread_handle; - int result_code = pthread_create( - &thread_handle, - &attr, - &StartCallbackPthreads, - this); - pthread_attr_destroy(&attr); - - return result_code; + xe_pal_ref pal = debugger_->pal(); + thread_ = xe_thread_create(pal, "Debugger Client", + StartCallback, this); + xe_pal_release(pal); + return xe_thread_start(thread_); } -void* WsClient::StartCallbackPthreads(void* param) { - WsClient* thread = reinterpret_cast(param); - thread->EventThread(); - return 0; +void WsClient::StartCallback(void* param) { + WsClient* client = reinterpret_cast(param); + client->EventThread(); } namespace { diff --git a/src/xenia/dbg/ws_client.h b/src/xenia/dbg/ws_client.h index 1246766cb..982370bbc 100644 --- a/src/xenia/dbg/ws_client.h +++ b/src/xenia/dbg/ws_client.h @@ -37,11 +37,13 @@ public: virtual void Write(uint8_t** buffers, size_t* lengths, size_t count); private: - static void* StartCallbackPthreads(void* param); + static void StartCallback(void* param); int PerformHandshake(); void EventThread(); + xe_thread_ref thread_; + int socket_id_; int notify_rd_id_;