mirror of
https://github.com/ValveSoftware/Proton.git
synced 2025-01-27 05:58:16 +03:00
lsteamclient: Execute SteamNetworkingSocketsDebugOutput callback from a Wine thread.
CW-Bug-Id: #20684 The callback is called from a native Unix thread which is not initialized with Wine, meaning it, e. g., has a leftover TEB from another thread. Only native Unix functions may be called from such a thread.
This commit is contained in:
parent
8d7d5bb129
commit
47ae0819ae
@ -4,6 +4,8 @@
|
|||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
@ -28,6 +30,17 @@ char g_tmppath[PATH_MAX];
|
|||||||
|
|
||||||
static CRITICAL_SECTION steamclient_cs = { NULL, -1, 0, 0, 0, 0 };
|
static CRITICAL_SECTION steamclient_cs = { NULL, -1, 0, 0, 0, 0 };
|
||||||
static HANDLE steam_overlay_event;
|
static HANDLE steam_overlay_event;
|
||||||
|
static HANDLE callback_thread_handle;
|
||||||
|
|
||||||
|
#define MAX_CALLBACK_QUEUE_SIZE 4
|
||||||
|
struct callback_data *callback_queue[MAX_CALLBACK_QUEUE_SIZE];
|
||||||
|
static unsigned int callback_queue_size;
|
||||||
|
static BOOL callback_queue_done;
|
||||||
|
static UINT64 callback_queue_current_seq_number;
|
||||||
|
static pthread_mutex_t callback_queue_mutex;
|
||||||
|
static pthread_cond_t callback_queue_callback_event;
|
||||||
|
static pthread_cond_t callback_queue_ready_event;
|
||||||
|
static pthread_cond_t callback_queue_complete_event;
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
|
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
|
||||||
{
|
{
|
||||||
@ -40,6 +53,22 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
|
|||||||
steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated");
|
steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated");
|
||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
|
if (callback_thread_handle)
|
||||||
|
{
|
||||||
|
/* Unfortunately we don't have a clear place to shutdown the thread so just kill it. */
|
||||||
|
/* An explicit sync events and handle cleanup is to protect from unloading and loading
|
||||||
|
* .so again which may end up not actually reloading anyting and leaving the values of our static
|
||||||
|
* variables. */
|
||||||
|
TerminateThread(callback_thread_handle, -1);
|
||||||
|
WaitForSingleObject(callback_thread_handle, INFINITE);
|
||||||
|
pthread_mutex_destroy(&callback_queue_mutex);
|
||||||
|
pthread_cond_destroy(&callback_queue_callback_event);
|
||||||
|
pthread_cond_destroy(&callback_queue_ready_event);
|
||||||
|
pthread_cond_destroy(&callback_queue_complete_event);
|
||||||
|
CloseHandle(callback_thread_handle);
|
||||||
|
callback_thread_handle = NULL;
|
||||||
|
TRACE("Terminated callback thread.\n");
|
||||||
|
}
|
||||||
CloseHandle(steam_overlay_event);
|
CloseHandle(steam_overlay_event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -573,6 +602,84 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void execute_callback(struct callback_data *cb_data)
|
||||||
|
{
|
||||||
|
/* No TRACEs or other Wine calls here, this is executed from Unix native thread
|
||||||
|
* which is not initialized by Wine. */
|
||||||
|
cb_data->complete = FALSE;
|
||||||
|
pthread_mutex_lock(&callback_queue_mutex);
|
||||||
|
while (!callback_queue_done && callback_queue_size == MAX_CALLBACK_QUEUE_SIZE)
|
||||||
|
pthread_cond_wait(&callback_queue_ready_event, &callback_queue_mutex);
|
||||||
|
if (callback_queue_done)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&callback_queue_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback_queue[callback_queue_size++] = cb_data;
|
||||||
|
pthread_cond_broadcast(&callback_queue_callback_event);
|
||||||
|
while (!callback_queue_done && !cb_data->complete)
|
||||||
|
pthread_cond_wait(&callback_queue_complete_event, &callback_queue_mutex);
|
||||||
|
pthread_mutex_unlock(&callback_queue_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL get_next_callback(struct callback_data *cb_data, UINT64 *cookie)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&callback_queue_mutex);
|
||||||
|
while (!callback_queue_done && !callback_queue_size)
|
||||||
|
pthread_cond_wait(&callback_queue_callback_event, &callback_queue_mutex);
|
||||||
|
|
||||||
|
if ((ret = !callback_queue_done))
|
||||||
|
{
|
||||||
|
assert(callback_queue_size);
|
||||||
|
--callback_queue_size;
|
||||||
|
*cookie = (UINT64)(ULONG_PTR)callback_queue[callback_queue_size];
|
||||||
|
*cb_data = *callback_queue[callback_queue_size];
|
||||||
|
}
|
||||||
|
pthread_cond_broadcast(&callback_queue_ready_event);
|
||||||
|
pthread_mutex_unlock(&callback_queue_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callback_complete(UINT64 cookie)
|
||||||
|
{
|
||||||
|
struct callback_data *cb_data = (struct callback_data *)(ULONG_PTR)cookie;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&callback_queue_mutex);
|
||||||
|
cb_data->complete = TRUE;
|
||||||
|
pthread_cond_broadcast(&callback_queue_complete_event);
|
||||||
|
pthread_mutex_unlock(&callback_queue_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (WINAPI *win_FSteamNetworkingSocketsDebugOutput)(ESteamNetworkingSocketsDebugOutputType nType,
|
||||||
|
const char *pszMsg);
|
||||||
|
|
||||||
|
static DWORD WINAPI callback_thread(void *dummy)
|
||||||
|
{
|
||||||
|
struct callback_data cb_data;
|
||||||
|
UINT64 cookie;
|
||||||
|
|
||||||
|
while (get_next_callback( &cb_data, &cookie))
|
||||||
|
{
|
||||||
|
switch (cb_data.type)
|
||||||
|
{
|
||||||
|
case SOCKET_DEBUG_OUTPUT:
|
||||||
|
TRACE("SOCKET_DEBUG_OUTPUT func %p, type %u, msg %s.\n",
|
||||||
|
cb_data.func, cb_data.sockets_debug_output.type,
|
||||||
|
wine_dbgstr_a(cb_data.sockets_debug_output.msg));
|
||||||
|
((win_FSteamNetworkingSocketsDebugOutput)cb_data.func)(cb_data.sockets_debug_output.type,
|
||||||
|
cb_data.sockets_debug_output.msg);
|
||||||
|
callback_complete(cookie);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERR("Unexpected callback type %u.\n", cb_data.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void *steamclient_lib;
|
static void *steamclient_lib;
|
||||||
static void *(*steamclient_CreateInterface)(const char *name, int *return_code);
|
static void *(*steamclient_CreateInterface)(const char *name, int *return_code);
|
||||||
static bool (*steamclient_BGetCallback)(HSteamPipe a, CallbackMsg_t *b, int32 *c);
|
static bool (*steamclient_BGetCallback)(HSteamPipe a, CallbackMsg_t *b, int32 *c);
|
||||||
@ -583,6 +690,7 @@ static void (*steamclient_ReleaseThreadLocalMemory)(int);
|
|||||||
static int load_steamclient(void)
|
static int load_steamclient(void)
|
||||||
{
|
{
|
||||||
char path[PATH_MAX], resolved_path[PATH_MAX];
|
char path[PATH_MAX], resolved_path[PATH_MAX];
|
||||||
|
DWORD callback_thread_id;
|
||||||
|
|
||||||
if(steamclient_lib)
|
if(steamclient_lib)
|
||||||
return 1;
|
return 1;
|
||||||
@ -643,6 +751,14 @@ static int load_steamclient(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_mutex_init(&callback_queue_mutex, NULL);
|
||||||
|
pthread_cond_init(&callback_queue_callback_event, NULL);
|
||||||
|
pthread_cond_init(&callback_queue_ready_event, NULL);
|
||||||
|
pthread_cond_init(&callback_queue_complete_event, NULL);
|
||||||
|
|
||||||
|
callback_thread_handle = CreateThread(NULL, 0, callback_thread, NULL, 0, &callback_thread_id);
|
||||||
|
TRACE("Created callback thread 0x%04x.\n", callback_thread_id);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,29 @@ bool do_cb_wrap(HSteamPipe pipe, void *linux_side, bool (*cpp_func)(void *, Stea
|
|||||||
|
|
||||||
void *alloc_mem_for_iface(size_t size, const char *iface_version);
|
void *alloc_mem_for_iface(size_t size, const char *iface_version);
|
||||||
|
|
||||||
|
enum callback_type
|
||||||
|
{
|
||||||
|
SOCKET_DEBUG_OUTPUT = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct callback_data
|
||||||
|
{
|
||||||
|
enum callback_type type;
|
||||||
|
void *func;
|
||||||
|
int complete;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int type;
|
||||||
|
const char *msg;
|
||||||
|
}
|
||||||
|
sockets_debug_output;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void execute_callback(struct callback_data *cb_data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -293,13 +293,19 @@ void *create_LinuxISteamMatchmakingRulesResponse(void *win, const char *version)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***** FSteamNetworkingSocketsDebugOutput *****/
|
/***** FSteamNetworkingSocketsDebugOutput *****/
|
||||||
static void (__attribute__((ms_abi)) *stored_FSteamNetworkingSocketsDebugOutput)(ESteamNetworkingSocketsDebugOutputType nType, const char *pszMsg);
|
static void (__attribute__((ms_abi)) *stored_FSteamNetworkingSocketsDebugOutput)(ESteamNetworkingSocketsDebugOutputType nType, const char *pszMsg);
|
||||||
|
|
||||||
static void lin_FSteamNetworkingSocketsDebugOutput(ESteamNetworkingSocketsDebugOutputType nType, const char *pszMsg)
|
static void lin_FSteamNetworkingSocketsDebugOutput(ESteamNetworkingSocketsDebugOutputType nType, const char *pszMsg)
|
||||||
{
|
{
|
||||||
stored_FSteamNetworkingSocketsDebugOutput(nType, pszMsg);
|
struct callback_data cb_data = { 0 };
|
||||||
|
/* Only Unix native calls from here (not even TRACE):
|
||||||
|
* this is native Unix thread which is not initialized by Wine. */
|
||||||
|
cb_data.type = SOCKET_DEBUG_OUTPUT;
|
||||||
|
cb_data.func = stored_FSteamNetworkingSocketsDebugOutput;
|
||||||
|
cb_data.sockets_debug_output.type = nType;
|
||||||
|
cb_data.sockets_debug_output.msg = pszMsg;
|
||||||
|
execute_callback(&cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *manual_convert_FSteamNetworkingSocketsDebugOutput(void *win_func)
|
void *manual_convert_FSteamNetworkingSocketsDebugOutput(void *win_func)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user