Add new platform thread callbacks for Windows RT usage to avoid banned APIs

This commit is contained in:
Cameron Gutman 2014-10-31 21:32:39 -07:00
parent 91f0351671
commit 7fb3ef3f79
6 changed files with 107 additions and 71 deletions

View File

@ -4,6 +4,7 @@
static int stage = STAGE_NONE; static int stage = STAGE_NONE;
static CONNECTION_LISTENER_CALLBACKS listenerCallbacks; static CONNECTION_LISTENER_CALLBACKS listenerCallbacks;
static CONNECTION_LISTENER_CALLBACKS originalCallbacks; static CONNECTION_LISTENER_CALLBACKS originalCallbacks;
static PLATFORM_CALLBACKS platformCallbacks;
static int alreadyTerminated; static int alreadyTerminated;
@ -134,12 +135,19 @@ void ClInternalDisplayTransientMessage(char* message)
originalCallbacks.displayTransientMessage(message); originalCallbacks.displayTransientMessage(message);
} }
void LiCompleteThreadStart(void)
{
PltRunThreadProc();
}
/* Starts the connection to the streaming machine */ /* Starts the connection to the streaming machine */
int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks, int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks,
PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, void* renderContext, int drFlags) { PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, PPLATFORM_CALLBACKS plCallbacks,
void* renderContext, int drFlags) {
int err; int err;
memcpy(&originalCallbacks, clCallbacks, sizeof(originalCallbacks)); memcpy(&originalCallbacks, clCallbacks, sizeof(originalCallbacks));
memcpy(&platformCallbacks, plCallbacks, sizeof(platformCallbacks));
listenerCallbacks.stageStarting = ClInternalStageStarting; listenerCallbacks.stageStarting = ClInternalStageStarting;
listenerCallbacks.stageComplete = ClInternalStageComplete; listenerCallbacks.stageComplete = ClInternalStageComplete;
@ -153,13 +161,13 @@ int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONN
Limelog("Initializing platform..."); Limelog("Initializing platform...");
listenerCallbacks.stageStarting(STAGE_PLATFORM_INIT); listenerCallbacks.stageStarting(STAGE_PLATFORM_INIT);
err = initializePlatformSockets(); err = initializePlatformSockets(&platformCallbacks);
if (err != 0) { if (err != 0) {
Limelog("failed: %d\n", err); Limelog("failed: %d\n", err);
listenerCallbacks.stageFailed(STAGE_PLATFORM_INIT, err); listenerCallbacks.stageFailed(STAGE_PLATFORM_INIT, err);
goto Cleanup; goto Cleanup;
} }
err = initializePlatformThreads(); err = initializePlatformThreads(&platformCallbacks);
if (err != 0) { if (err != 0) {
Limelog("failed: %d\n", err); Limelog("failed: %d\n", err);
listenerCallbacks.stageFailed(STAGE_PLATFORM_INIT, err); listenerCallbacks.stageFailed(STAGE_PLATFORM_INIT, err);

View File

@ -90,11 +90,21 @@ typedef struct _CONNECTION_LISTENER_CALLBACKS {
ConnListenerDisplayTransientMessage displayTransientMessage; ConnListenerDisplayTransientMessage displayTransientMessage;
} CONNECTION_LISTENER_CALLBACKS, *PCONNECTION_LISTENER_CALLBACKS; } CONNECTION_LISTENER_CALLBACKS, *PCONNECTION_LISTENER_CALLBACKS;
typedef void(*PlatformThreadStart)(void);
typedef struct _PLATFORM_CALLBACKS {
PlatformThreadStart threadStart;
} PLATFORM_CALLBACKS, *PPLATFORM_CALLBACKS;
int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks, int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks,
PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, void* renderContext, int drFlags); PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, PPLATFORM_CALLBACKS plCallbacks,
void* renderContext, int drFlags);
void LiStopConnection(void); void LiStopConnection(void);
const char* LiGetStageName(int stage); const char* LiGetStageName(int stage);
/* Call in the context of a new thread */
void LiCompleteThreadStart(void);
int LiSendMouseMoveEvent(short deltaX, short deltaY); int LiSendMouseMoveEvent(short deltaX, short deltaY);
#define BUTTON_ACTION_PRESS 0x07 #define BUTTON_ACTION_PRESS 0x07

View File

@ -80,7 +80,7 @@ int enableNoDelay(SOCKET s) {
return 0; return 0;
} }
int initializePlatformSockets(void) { int initializePlatformSockets(PPLATFORM_CALLBACKS plCallbacks) {
#if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE) #if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE)
WSADATA data; WSADATA data;
return WSAStartup(MAKEWORD(2, 0), &data); return WSAStartup(MAKEWORD(2, 0), &data);

View File

@ -33,5 +33,5 @@ typedef ssize_t SOCK_RET;
SOCKET connectTcpSocket(IP_ADDRESS dstaddr, unsigned short port); SOCKET connectTcpSocket(IP_ADDRESS dstaddr, unsigned short port);
SOCKET bindUdpSocket(void); SOCKET bindUdpSocket(void);
int enableNoDelay(SOCKET s); int enableNoDelay(SOCKET s);
int initializePlatformSockets(void); int initializePlatformSockets(PPLATFORM_CALLBACKS plCallbacks);
void cleanupPlatformSockets(void); void cleanupPlatformSockets(void);

View File

@ -1,28 +1,15 @@
#include "PlatformThreads.h" #include "PlatformThreads.h"
#include "Platform.h" #include "Platform.h"
struct thread_context {
ThreadEntry entry;
void* context;
};
#if defined(LC_WINDOWS_PHONE) || defined(LC_WINDOWS) #if defined(LC_WINDOWS_PHONE) || defined(LC_WINDOWS)
WCHAR DbgBuf[512]; WCHAR DbgBuf[512];
#endif #endif
#if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE) #if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE)
PLT_MUTEX thread_list_lock; PLT_MUTEX thread_list_lock;
PLT_THREAD *pending_thread_head;
PLT_THREAD *thread_head; PLT_THREAD *thread_head;
PPLATFORM_CALLBACKS platformCallbacks;
DWORD WINAPI ThreadProc(LPVOID lpParameter) {
struct thread_context *ctx = (struct thread_context *)lpParameter;
ctx->entry(ctx->context);
free(ctx);
return 0;
}
#else #else
void* ThreadProc(void* context) { void* ThreadProc(void* context) {
struct thread_context *ctx = (struct thread_context *)context; struct thread_context *ctx = (struct thread_context *)context;
@ -86,7 +73,8 @@ void PltUnlockMutex(PLT_MUTEX *mutex) {
void PltJoinThread(PLT_THREAD *thread) { void PltJoinThread(PLT_THREAD *thread) {
#if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE) #if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE)
WaitForSingleObjectEx(thread->handle, INFINITE, FALSE); // Wait for the thread to leave our code
WaitForSingleObjectEx(thread->termCompleted, INFINITE, FALSE);
#else #else
pthread_join(*thread, NULL); pthread_join(*thread, NULL);
#endif #endif
@ -123,8 +111,8 @@ void PltCloseThread(PLT_THREAD *thread) {
PltUnlockMutex(&thread_list_lock); PltUnlockMutex(&thread_list_lock);
CloseHandle(thread->termevent); CloseHandle(thread->termRequested);
CloseHandle(thread->handle); CloseHandle(thread->termCompleted);
#else #else
#endif #endif
} }
@ -142,12 +130,47 @@ int PltIsThreadInterrupted(PLT_THREAD *thread) {
void PltInterruptThread(PLT_THREAD *thread) { void PltInterruptThread(PLT_THREAD *thread) {
#if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE) #if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE)
thread->cancelled = 1; thread->cancelled = 1;
SetEvent(thread->termevent); SetEvent(thread->termRequested);
#else #else
pthread_cancel(*thread); pthread_cancel(*thread);
#endif #endif
} }
void PltRunThreadProc(void) {
#if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE)
PLT_THREAD *thread;
// Grab the first entry from the pending list and move it
// to the active list
PltLockMutex(&thread_list_lock);
thread = pending_thread_head;
// If there's no pending thread, something is seriously wrong
LC_ASSERT(thread != NULL);
pending_thread_head = pending_thread_head->next;
thread->next = thread_head;
thread_head = thread;
PltUnlockMutex(&thread_list_lock);
// Set up final thread state before running
thread->tid = GetCurrentThreadId();
// Now we're going to invoke the thread proc
thread->ctx->entry(thread->ctx->context);
free(thread->ctx);
// Signal the event to indicate the thread has "terminated"
SetEvent(thread->termCompleted);
// PltCloseThread() frees this state
#else
// This code shouldn't be called on *NIX
LC_ASSERT(0);
#endif
}
int PltCreateThread(ThreadEntry entry, void* context, PLT_THREAD *thread) { int PltCreateThread(ThreadEntry entry, void* context, PLT_THREAD *thread) {
struct thread_context *ctx; struct thread_context *ctx;
int err; int err;
@ -162,32 +185,32 @@ int PltCreateThread(ThreadEntry entry, void* context, PLT_THREAD *thread) {
#if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE) #if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE)
{ {
thread->termevent = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); thread->termRequested = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
if (thread->termevent == NULL) { if (thread->termRequested == NULL) {
free(ctx); free(ctx);
return -1; return -1;
} }
thread->termCompleted = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
if (thread->termCompleted == NULL) {
CloseHandle(thread->termRequested);
free(ctx);
return -1;
}
thread->cancelled = 0; thread->cancelled = 0;
// TODO we aren't allowed to use CreateThread API in kernel32.dll thread->ctx = ctx;
thread->handle = CreateThread(NULL, 0, ThreadProc, ctx, CREATE_SUSPENDED, &thread->tid);
if (thread->handle == NULL) {
CloseHandle(thread->termevent);
free(ctx);
return -1;
}
else {
// Add this thread to the thread list
PltLockMutex(&thread_list_lock);
thread->next = thread_head;
thread_head = thread;
PltUnlockMutex(&thread_list_lock);
// Now the thread can run // Queue on the pending threads list
// TODO can't use ResumeThread in kernel32.dll PltLockMutex(&thread_list_lock);
ResumeThread(thread->handle); thread->next = pending_thread_head;
pending_thread_head = thread;
PltUnlockMutex(&thread_list_lock);
err = 0; // Make a callback to managed code to ask for a thread to grab this
} platformCallbacks->threadStart();
err = 0;
} }
#else #else
{ {
@ -263,7 +286,7 @@ int PltWaitForEvent(PLT_EVENT *event) {
LC_ASSERT(current_thread != NULL); LC_ASSERT(current_thread != NULL);
objects[0] = *event; objects[0] = *event;
objects[1] = current_thread->termevent; objects[1] = current_thread->termRequested;
error = WaitForMultipleObjectsEx(2, objects, FALSE, INFINITE, FALSE); error = WaitForMultipleObjectsEx(2, objects, FALSE, INFINITE, FALSE);
if (error == WAIT_OBJECT_0) { if (error == WAIT_OBJECT_0) {
return PLT_WAIT_SUCCESS; return PLT_WAIT_SUCCESS;
@ -285,8 +308,14 @@ int PltWaitForEvent(PLT_EVENT *event) {
#endif #endif
} }
int initializePlatformThreads(void) { int initializePlatformThreads(PPLATFORM_CALLBACKS plCallbacks) {
#if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE) #if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE)
pending_thread_head = thread_head = NULL;
// This data is stored in static memory in Connection.c, so we don't
// bother making our own copy
platformCallbacks = plCallbacks;
return PltCreateMutex(&thread_list_lock); return PltCreateMutex(&thread_list_lock);
#else #else
return 0; return 0;

View File

@ -1,15 +1,23 @@
#pragma once #pragma once
#include "Limelight.h"
#include "Platform.h" #include "Platform.h"
typedef void (*ThreadEntry)(void *context); typedef void (*ThreadEntry)(void *context);
struct thread_context {
ThreadEntry entry;
void* context;
};
#if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE) #if defined(LC_WINDOWS) || defined(LC_WINDOWS_PHONE)
typedef struct _PLT_THREAD { typedef struct _PLT_THREAD {
HANDLE handle;
int cancelled; int cancelled;
DWORD tid; DWORD tid;
HANDLE termevent; HANDLE termRequested;
HANDLE termCompleted;
struct thread_context *ctx;
struct _PLT_THREAD *next; struct _PLT_THREAD *next;
} PLT_THREAD; } PLT_THREAD;
@ -27,28 +35,7 @@ typedef struct _PLT_EVENT {
#error Unsupported platform #error Unsupported platform
#endif #endif
#ifdef LC_WINDOWS_PHONE int initializePlatformThreads(PPLATFORM_CALLBACKS plCallbacks);
WINBASEAPI
_Ret_maybenull_
HANDLE
WINAPI
CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ __drv_aliasesMem LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);
DWORD
WINAPI
ResumeThread(
_In_ HANDLE hThread
);
#endif
int initializePlatformThreads(void);
void cleanupPlatformThreads(void); void cleanupPlatformThreads(void);
int PltCreateMutex(PLT_MUTEX *mutex); int PltCreateMutex(PLT_MUTEX *mutex);
@ -68,6 +55,8 @@ void PltSetEvent(PLT_EVENT *event);
void PltClearEvent(PLT_EVENT *event); void PltClearEvent(PLT_EVENT *event);
int PltWaitForEvent(PLT_EVENT *event); int PltWaitForEvent(PLT_EVENT *event);
void PltRunThreadProc(void);
#define PLT_WAIT_SUCCESS 0 #define PLT_WAIT_SUCCESS 0
#define PLT_WAIT_INTERRUPTED 1 #define PLT_WAIT_INTERRUPTED 1