Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix compilation with MSVC14 and C++14 compilers, and gets rid of pthread-win32 #136

Merged
merged 6 commits into from Aug 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/chipmunk.c
Expand Up @@ -56,7 +56,7 @@ cpMessage(const char *condition, const char *file, int line, int isError, int is
#define STR(s) #s
#define XSTR(s) STR(s)

const char *cpVersionString = XSTR(CP_VERSION_MAJOR)"." XSTR(CP_VERSION_MINOR)"." XSTR(CP_VERSION_RELEASE);
const char *cpVersionString = XSTR(CP_VERSION_MAJOR) "." XSTR(CP_VERSION_MINOR) "." XSTR(CP_VERSION_RELEASE);

//MARK: Misc Functions

Expand Down
204 changes: 202 additions & 2 deletions src/cpHastySpace.c
Expand Up @@ -4,10 +4,210 @@
#include <stdlib.h>
#include <stdio.h>

#include <pthread.h>
//TODO: Move all the thread stuff to another file

//#include <sys/param.h >
#ifndef _WIN32
#include <sys/sysctl.h>
#include <pthread.h>
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#ifndef NOMINMAX
#define NOMINMAX
#endif

#include <process.h> // _beginthreadex
#include <windows.h>

#ifndef ETIMEDOUT
#define ETIMEDOUT 1
#endif

// Simple pthread implementation for Windows
// Made from scratch to avoid the LGPL licence from pthread-win32
enum {
SIGNAL = 0,
BROADCAST = 1,
MAX_EVENTS = 2
};

typedef HANDLE pthread_t;
typedef struct
{
// Based on http://www.cs.wustl.edu/~schmidt/win32-cv-1.html since Windows has no condition variable until NT6
UINT waiters_count;
// Count of the number of waiters.

CRITICAL_SECTION waiters_count_lock;
// Serialize access to <waiters_count_>.

HANDLE events[MAX_EVENTS];
} pthread_cond_t;
typedef CRITICAL_SECTION pthread_mutex_t;

typedef struct {} pthread_condattr_t; // Dummy;

int pthread_cond_destroy(pthread_cond_t* cv)
{
CloseHandle(cv->events[BROADCAST]);
CloseHandle(cv->events[SIGNAL]);

DeleteCriticalSection(&cv->waiters_count_lock);

return 0;
}

int pthread_cond_init(pthread_cond_t* cv, const pthread_condattr_t* attr)
{
// Initialize the count to 0.
cv->waiters_count = 0;

// Create an auto-reset event.
cv->events[SIGNAL] = CreateEvent(NULL, // no security
FALSE, // auto-reset event
FALSE, // non-signaled initially
NULL); // unnamed

// Create a manual-reset event.
cv->events[BROADCAST] = CreateEvent(NULL, // no security
TRUE, // manual-reset
FALSE, // non-signaled initially
NULL); // unnamed

InitializeCriticalSection(&cv->waiters_count_lock);

return 0;
}

int pthread_cond_broadcast(pthread_cond_t *cv)
{
// Avoid race conditions.
EnterCriticalSection(&cv->waiters_count_lock);
int have_waiters = cv->waiters_count > 0;
LeaveCriticalSection(&cv->waiters_count_lock);

if (have_waiters)
SetEvent(cv->events[BROADCAST]);

return 0;
}

int pthread_cond_signal(pthread_cond_t* cv)
{
// Avoid race conditions.
EnterCriticalSection(&cv->waiters_count_lock);
int have_waiters = cv->waiters_count > 0;
LeaveCriticalSection(&cv->waiters_count_lock);

if (have_waiters)
SetEvent(cv->events[SIGNAL]);

return 0;
}

int pthread_cond_wait(pthread_cond_t* cv, pthread_mutex_t* external_mutex)
{
// Avoid race conditions.
EnterCriticalSection(&cv->waiters_count_lock);
cv->waiters_count++;
LeaveCriticalSection(&cv->waiters_count_lock);

// It's ok to release the <external_mutex> here since Win32
// manual-reset events maintain state when used with
// <SetEvent>. This avoids the "lost wakeup" bug...
LeaveCriticalSection(external_mutex);

// Wait for either event to become signaled due to <pthread_cond_signal>
// being called or <pthread_cond_broadcast> being called.
int result = WaitForMultipleObjects(2, cv->events, FALSE, INFINITE);

EnterCriticalSection(&cv->waiters_count_lock);
cv->waiters_count--;
int last_waiter =
result == WAIT_OBJECT_0 + BROADCAST
&& cv->waiters_count == 0;
LeaveCriticalSection(&cv->waiters_count_lock);

// Some thread called <pthread_cond_broadcast>.
if (last_waiter)
// We're the last waiter to be notified or to stop waiting, so
// reset the manual event.
ResetEvent(cv->events[BROADCAST]);

// Reacquire the <external_mutex>.
EnterCriticalSection(external_mutex);

return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
}

typedef struct {} pthread_mutexattr_t; //< Dummy

int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr)
{
InitializeCriticalSection(mutex);
return 0;
}

int pthread_mutex_destroy(pthread_mutex_t* mutex)
{
DeleteCriticalSection(mutex);
return 0;
}

int pthread_mutex_lock(pthread_mutex_t* mutex)
{
EnterCriticalSection(mutex);
return 0;
}

int pthread_mutex_unlock(pthread_mutex_t* mutex)
{
LeaveCriticalSection(mutex);
return 0;
}

typedef struct {} pthread_attr_t;

typedef struct
{
void *(*start_routine) (void *);
void* arg;
} pthread_internal_thread;

unsigned int __stdcall ThreadProc(void* userdata)
{
pthread_internal_thread* ud = (pthread_internal_thread*) userdata;
ud->start_routine(ud->arg);

free(ud);

return 0;
}

int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void *(*start_routine) (void *), void *arg)
{
pthread_internal_thread* ud = (pthread_internal_thread*) malloc(sizeof(pthread_internal_thread));
ud->start_routine = start_routine;
ud->arg = arg;

*thread = (HANDLE) (_beginthreadex(NULL, 0, &ThreadProc, ud, 0, NULL));
if (!*thread)
return 1;

return 0;
}

int pthread_join(pthread_t thread, void **value_ptr)
{
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);

return 0;
}

#endif

#include "chipmunk/chipmunk_private.h"
Expand Down Expand Up @@ -335,7 +535,7 @@ cpHastySpaceSetThreads(cpSpace *space, unsigned long threads)
hasty->workers[i].space = hasty;
hasty->workers[i].thread_num = i + 1;

pthread_create(&hasty->workers[i].thread, NULL, (void *)WorkerThreadLoop, &hasty->workers[i]);
pthread_create(&hasty->workers[i].thread, NULL, (void*(*)(void*))WorkerThreadLoop, &hasty->workers[i]);
}

pthread_cond_wait(&hasty->cond_resume, &hasty->mutex);
Expand Down
12 changes: 6 additions & 6 deletions src/cpPolyline.c
Expand Up @@ -49,7 +49,7 @@ static cpPolyline *
cpPolylineShrink(cpPolyline *line)
{
line->capacity = line->count;
return cprealloc(line, cpPolylineSizeForCapacity(line->count));
return (cpPolyline*) cprealloc(line, cpPolylineSizeForCapacity(line->count));
}

void
Expand All @@ -69,7 +69,7 @@ cpPolylineGrow(cpPolyline *line, int count)

if(line->capacity < capacity){
line->capacity = capacity;
line = cprealloc(line, cpPolylineSizeForCapacity(capacity));
line = (cpPolyline*) cprealloc(line, cpPolylineSizeForCapacity(capacity));
}

return line;
Expand Down Expand Up @@ -244,7 +244,7 @@ cpPolylineSetInit(cpPolylineSet *set)
{
set->count = 0;
set->capacity = 8;
set->lines = cpcalloc(set->capacity, sizeof(cpPolyline));
set->lines = (cpPolyline**) cpcalloc(set->capacity, sizeof(cpPolyline));

return set;
}
Expand Down Expand Up @@ -313,7 +313,7 @@ cpPolylineSetPush(cpPolylineSet *set, cpPolyline *line)
set->count++;
if(set->count > set->capacity){
set->capacity *= 2;
set->lines = cprealloc(set->lines, set->capacity*sizeof(cpPolyline));
set->lines = (cpPolyline**) cprealloc(set->lines, set->capacity*sizeof(cpPolyline));
}

set->lines[set->count - 1] = line;
Expand Down Expand Up @@ -599,7 +599,7 @@ static void
ApproximateConcaveDecomposition(cpVect *verts, int count, cpFloat tol, cpPolylineSet *set)
{
int first;
cpVect *hullVerts = alloca(count*sizeof(cpVect));
cpVect *hullVerts = (cpVect*) alloca(count*sizeof(cpVect));
int hullCount = cpConvexHull(count, verts, hullVerts, &first, 0.0);

if(hullCount != count){
Expand All @@ -615,7 +615,7 @@ ApproximateConcaveDecomposition(cpVect *verts, int count, cpFloat tol, cpPolylin
// Vertex counts NOT including the steiner point.
int sub1_count = (steiner_i - notch.i + count)%count + 1;
int sub2_count = count - (steiner_i - notch.i + count)%count;
cpVect *scratch = alloca((IMAX(sub1_count, sub2_count) + 1)*sizeof(cpVect));
cpVect *scratch = (cpVect*) alloca((IMAX(sub1_count, sub2_count) + 1)*sizeof(cpVect));

for(int i=0; i<sub1_count; i++) scratch[i] = verts[(notch.i + i)%count];
scratch[sub1_count] = steiner;
Expand Down