Fix a race condition where PltCloseThread was called before the thread was inserted into the list

This commit is contained in:
Cameron Gutman
2016-02-16 19:35:54 -05:00
parent ca870694ba
commit 00283a7267
2 changed files with 32 additions and 12 deletions
+22 -4
View File
@@ -41,6 +41,9 @@ void* ThreadProc(void* context) {
thread_head = ctx->thread; thread_head = ctx->thread;
PltUnlockMutex(&thread_list_lock); PltUnlockMutex(&thread_list_lock);
// Signal the event since the thread is now inserted
PltSetEvent(&ctx->thread->insertedEvent);
ctx->entry(ctx->context); ctx->entry(ctx->context);
free(ctx); free(ctx);
@@ -165,6 +168,8 @@ void PltCloseThread(PLT_THREAD* thread) {
PltUnlockMutex(&thread_list_lock); PltUnlockMutex(&thread_list_lock);
PltCloseEvent(&thread->insertedEvent);
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS)
CloseHandle(thread->termRequested); CloseHandle(thread->termRequested);
CloseHandle(thread->handle); CloseHandle(thread->handle);
@@ -195,36 +200,49 @@ int PltCreateThread(ThreadEntry entry, void* context, PLT_THREAD* thread) {
ctx->context = context; ctx->context = context;
ctx->thread = thread; ctx->thread = thread;
err = PltCreateEvent(&thread->insertedEvent);
if (err != 0) {
free(ctx);
return err;
}
thread->cancelled = 0; thread->cancelled = 0;
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS)
{ {
thread->termRequested = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); thread->termRequested = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
if (thread->termRequested == NULL) { if (thread->termRequested == NULL) {
PltCloseEvent(&thread->insertedEvent);
free(ctx); free(ctx);
return -1; return -1;
} }
thread->handle = CreateThread(NULL, 0, ThreadProc, ctx, 0, &thread->tid); thread->handle = CreateThread(NULL, 0, ThreadProc, ctx, 0, &thread->tid);
if (thread->handle == NULL) { if (thread->handle == NULL) {
PltCloseEvent(&thread->insertedEvent);
CloseHandle(thread->termRequested); CloseHandle(thread->termRequested);
free(ctx); free(ctx);
return -1; return -1;
} }
else {
err = 0;
}
} }
#else #else
{ {
err = pthread_create(&thread->thread, NULL, ThreadProc, ctx); err = pthread_create(&thread->thread, NULL, ThreadProc, ctx);
if (err != 0) { if (err != 0) {
PltCloseEvent(&thread->insertedEvent);
free(ctx); free(ctx);
return err;
} }
} }
#endif #endif
return err; // We shouldn't get this far with an error
LC_ASSERT(err == 0);
// Wait for the thread to be started and inserted into the active threads list
PltWaitForEvent(&thread->insertedEvent);
return 0;
} }
int PltCreateEvent(PLT_EVENT* event) { int PltCreateEvent(PLT_EVENT* event) {
+10 -8
View File
@@ -6,29 +6,31 @@
typedef void(*ThreadEntry)(void* context); typedef void(*ThreadEntry)(void* context);
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS)
typedef HANDLE PLT_MUTEX;
typedef HANDLE PLT_EVENT;
typedef struct _PLT_THREAD { typedef struct _PLT_THREAD {
HANDLE handle; HANDLE handle;
int cancelled; int cancelled;
DWORD tid; DWORD tid;
HANDLE termRequested; HANDLE termRequested;
PLT_EVENT insertedEvent;
struct _PLT_THREAD* next; struct _PLT_THREAD* next;
} PLT_THREAD; } PLT_THREAD;
typedef HANDLE PLT_MUTEX;
typedef HANDLE PLT_EVENT;
#elif defined (LC_POSIX) #elif defined (LC_POSIX)
typedef struct _PLT_THREAD {
pthread_t thread;
int cancelled;
struct _PLT_THREAD* next;
} PLT_THREAD;
typedef pthread_mutex_t PLT_MUTEX; typedef pthread_mutex_t PLT_MUTEX;
typedef struct _PLT_EVENT { typedef struct _PLT_EVENT {
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cond; pthread_cond_t cond;
int signalled; int signalled;
} PLT_EVENT; } PLT_EVENT;
typedef struct _PLT_THREAD {
pthread_t thread;
int cancelled;
PLT_EVENT insertedEvent;
struct _PLT_THREAD* next;
} PLT_THREAD;
#else #else
#error Unsupported platform #error Unsupported platform
#endif #endif