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;
+	}
+}
+