Mercurial > almixer_isolated
changeset 59:7d508c8cd75a
New implementation backend for SimpleThread using native Windows threading APIs.
Documentation found here:
http://msdn.microsoft.com/en-us/library/kdzttdcb(v=vs.110).aspx
Web searches indicated I should be using _beginthreadex instead of CreateThread for C runtime compatibility.
author | Eric Wing <ewing . public |-at-| gmail . com> |
---|---|
date | Fri, 08 Jun 2012 01:04:51 -0700 |
parents | 79503033cf53 |
children | f7acef5a80fe |
files | Isolated/SimpleThreadWindows.c |
diffstat | 1 files changed, 200 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Isolated/SimpleThreadWindows.c Fri Jun 08 01:04:51 2012 -0700 @@ -0,0 +1,200 @@ +/* Copyright PlayControl Software LLC / Eric Wing. + */ +#include "SimpleThread.h" + +#define WIN32_LEAN_AND_MEAN +#include <process.h> +#include <windows.h> + +#if defined(DEBUG) +#include <stdio.h> +#define THRDDBG(x) printf x +#else +#define THRDDBG(x) +#endif + + +struct SimpleThread +{ + unsigned threadID; + uintptr_t nativeThread; + unsigned threadStatus; +// void* userData; +}; + +typedef struct SimpleThreadArguments +{ + int (*userFunction)(void*); + void* userData; + SimpleThread* simpleThread; +} SimpleThreadArguments; + + + +static unsigned Internal_RunThread(void* user_data) +{ + int (*user_function)(void*); + void* function_user_data; + int* status_val; + +#if 0 + /* disable signals */ + sigset_t disable_set; + + /* + in the main thread, set up the desired signal mask, common to most threads + any newly created threads will inherit this signal mask + */ + sigemptyset(&disable_set); + sigaddset(&disable_set, SIGHUP); + sigaddset(&disable_set, SIGINT); + sigaddset(&disable_set, SIGUSR1); + sigaddset(&disable_set, SIGUSR2); + sigaddset(&disable_set, SIGALRM); + sigaddset(&disable_set, SIGQUIT); + sigaddset(&disable_set, SIGPIPE); + sigaddset(&disable_set, SIGTERM); + sigaddset(&disable_set, SIGCHLD); + sigaddset(&disable_set, SIGWINCH); + sigaddset(&disable_set, SIGVTALRM); + sigaddset(&disable_set, SIGPROF); + + + /* block out these signals */ + sigprocmask(SIG_BLOCK, &disable_set, NULL); +#endif + + SimpleThreadArguments* simple_thread_arguments = (SimpleThreadArguments*)user_data; + /* It looks like the last parameter of _beginthreadex sets the threadID for me */ +/* simple_thread_arguments->simpleThread->threadID = SimpleThread_GetCurrentThreadID(); */ + + user_function = simple_thread_arguments->userFunction; + function_user_data = simple_thread_arguments->userData; + status_val = &simple_thread_arguments->simpleThread->threadStatus; + + + /* I hope this is safe to delete on a different thread than it was created for. */ + free(simple_thread_arguments); + + *status_val = user_function(function_user_data); + + _endthreadex( 0 ); + + return NULL; +} + + +SimpleThread* SimpleThread_CreateThread(int (*user_function)(void*), void* user_data) +{ + int ret_val; + SimpleThread* new_thread; + SimpleThreadArguments* simple_thread_arguments; + + new_thread = (SimpleThread*)malloc(sizeof(SimpleThread)); + if(NULL == new_thread) + { + THRDDBG(("Out of memory.\n")); + return NULL; + } + + simple_thread_arguments = (SimpleThreadArguments*)malloc(sizeof(SimpleThreadArguments)); + if(NULL == simple_thread_arguments) + { + THRDDBG(("Out of memory.\n")); + free(new_thread); + return NULL; + } + simple_thread_arguments->userFunction = user_function; + simple_thread_arguments->userData = user_data; + simple_thread_arguments->simpleThread = new_thread; + + + new_thread->nativeThread = _beginthreadex(NULL, 0, &Internal_RunThread, simple_thread_arguments, 0, &new_thread->threadID); + if(0 == ret_val) + { + THRDDBG(("_beginthreadex failed with: %d\n", errno)); + free(simple_thread_arguments); + free(new_thread); + return NULL; + } + + return new_thread; +} + + + +size_t SimpleThread_GetCurrentThreadID() +{ + return (size_t)GetCurrentThreadId(); +} + +void SimpleThread_WaitThread(SimpleThread* simple_thread, int* thread_status) +{ + int ret_val; + if(NULL == simple_thread) + { + THRDDBG(("SimpleThread_WaitThread was passed NULL\n")); + return; + } + + WaitForSingleObject(simple_thread->nativeThread, INFINITE); + CloseHandle(simple_thread->nativeThread); + + if(NULL != thread_status) + { + *thread_status = (int)simple_thread->threadStatus; + } + free(simple_thread); +} + +size_t SimpleThread_GetThreadID(SimpleThread* simple_thread) +{ + if(NULL == simple_thread) + { + THRDDBG(("SimpleThread_GetThreadID was passed NULL\n")); + return 0; + } + return (size_t)simple_thread->threadID; +} + +/* TODO: Figure out portable/normalized range for levels */ +int SimpleThread_GetThreadPriority(SimpleThread* simple_thread) +{ + struct sched_param schedule_param; + int sched_policy; + int ret_val; + + if(NULL == simple_thread) + { + THRDDBG(("SimpleThread_GetThreadPriority was passed NULL\n")); + return THREAD_PRIORITY_ERROR_RETURN; /* Windows ranges seem to go from -15 to +15 */ + } + ret_val = GetThreadPriority(simple_thread->nativeThread); + if(THREAD_PRIORITY_ERROR_RETURN == ret_val) + { + THRDDBG(("SimpleThread_GetThreadPriority GetThreadPriority failed with: %d\n", ret_val)); + return THREAD_PRIORITY_ERROR_RETURN; + } + return ret_val; +} + +/* TODO: Figure out portable/normalized range for levels */ +void SimpleThread_SetThreadPriority(SimpleThread* simple_thread, int priority_level) +{ + struct sched_param schedule_param; + BOOL ret_val; + + if(NULL == simple_thread) + { + THRDDBG(("SimpleThread_SetThreadPriority was passed NULL\n")); + return; + } + + ret_val = SetThreadPriority(simple_thread->nativeThread, priority_level); + if(0 == ret_val) + { + THRDDBG(("SimpleThread_SetThreadPriority SetThreadPriority failed")); + return; + } +} +