diff options
-rw-r--r-- | meson.build | 74 | ||||
-rw-r--r-- | src/windows/threads.h | 274 |
2 files changed, 334 insertions, 14 deletions
diff --git a/meson.build b/meson.build index a8bd4ae..611408f 100644 --- a/meson.build +++ b/meson.build @@ -1,32 +1,78 @@ -project('Pong', 'c', license : 'GPL-3.0-only', version : '0.2', default_options : ['warning_level=3', 'werror=true', 'optimization=g', 'c_std=c11', 'prefix=/opt']) -add_project_link_arguments('../raylib/libraylib.a', '-lm', '-ldl', '-lrt', language : 'c') +project('Pong', 'c', license : 'GPL-3.0-only', version : '0.2', default_options : ['warning_level=3', 'werror=false', 'optimization=g', 'c_std=c11', 'prefix=/opt']) fs = import('fs') +# Checks if on UNIX/POSIX System +if host_machine.system() != 'windows' + if host_machine.system() != 'darwin' + set_variable('posix', true) + endif +else + set_variable('posix', false) +endif + +if get_variable('posix') == true + message('Cleaning raylib...') + # First clean up + run_command('make', '-C', 'raylib/src', 'clean', capture : true, check : true) + message('Building raylib...') + # Then Build + run_command('make', '-C', 'raylib/src', 'PLATFORM=PLATFORM_DESKTOP', 'RAYLIB_BUILD_MODE=RELEASE', capture : true, check : true) +else + message('Cleaning raylib...') + # Have to put OS_PLATFORM=linux or makefile will complain about del command not being found. + run_command('mingw32-make', '-C', 'raylib/src', 'PLATFORM_OS=linux', 'clean', capture : true, check : true) + message('Building raylib...') + run_command('mingw32-make', '-C', 'raylib/src', 'PLATFORM=PLATFORM_DESKTOP', 'RAYLIB_BUILD_MODE=RELEASE', capture : true, check : true) +endif -message('Cleaning raylib...') -# First clean up -run_command('make', '-C', 'raylib/src', 'clean', capture : true, check : true) -message('Building raylib...') -# Then Build -run_command('make', '-C', 'raylib/src', 'PLATFORM=PLATFORM_DESKTOP', 'RAYLIB_BUILD_MODE=RELEASE', capture : true, check : true) +# Find the static library if fs.exists('raylib/libraylib.a') == true - message('raylib successfully compiled.') + add_project_link_arguments('../raylib/libraylib.a', language : 'c') +elif fs.exists('raylib/src/libraylib.a') == true + add_project_link_arguments('../raylib/src/libraylib.a', language : 'c') else error('raylib failed to compile. Check meson-logs to see what went wrong.') endif -Raylib_Include = include_directories('raylib/src') +message('raylib successfully compiled.') + +Include_Directories = include_directories('raylib/src') # Install launcher if flatpak if get_option('build_flatpak') == true install_data('src/launch.sh', install_dir : 'bin') endif -X11_Dep = dependency('x11') -Threads_Dep = dependency('threads') +# Checks if on UNIX/POSIX System +if host_machine.system() != 'windows' + if host_machine.system() != 'darwin' + set_variable('posix', true) + endif +else + set_variable('posix', false) +endif + +if get_variable('posix') == true + X11_Dep = dependency('x11') +endif + GL_Dep = dependency('gl') +Threads_Dep = dependency('threads') Sources = ['src/main.c', 'src/enemy.c', 'src/ball.c', 'src/title.c', 'src/versus.c', 'src/marathon.c'] -executable('pong', Sources, dependencies : [X11_Dep, Threads_Dep, GL_Dep], install : true, install_dir : 'Pong', include_directories : Raylib_Include) -install_subdir('resources', install_dir : 'Pong') \ No newline at end of file +if get_variable('posix') == true + Dependencies = [GL_Dep, Threads_Dep, X11_Dep] + add_project_link_arguments('-lGL', '-lm', '-lpthread', '-ldl', '-lrt', '-lX11', language : 'c') +else + Dependencies = [GL_Dep, Threads_Dep] + add_project_link_arguments('-lopengl32', '-lgdi32', '-lwinmm', '-lpthread', '-lm', language : 'c') +endif + +# If on windows, we need the c11 threads emulation layer. +if get_variable('posix') == false + Include_Directories = include_directories(['raylib/src', 'src/windows']) +endif + +executable('pong', Sources, dependencies : Dependencies, install : true, install_dir : 'Pong', include_directories : Include_Directories) +install_subdir('resources', install_dir : 'Pong') diff --git a/src/windows/threads.h b/src/windows/threads.h new file mode 100644 index 0000000..7be02e5 --- /dev/null +++ b/src/windows/threads.h @@ -0,0 +1,274 @@ +/* +Author: John Tsiombikas <nuclear@member.fsf.org> + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somehwere, +but whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ + +#ifndef C11THREADS_H_ +#define C11THREADS_H_ + +#include <time.h> +#include <errno.h> +#include <pthread.h> +#include <sched.h> /* for sched_yield */ +#include <sys/time.h> + +#define thread_local _Thread_local +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT + +#ifdef __APPLE__ +/* Darwin doesn't implement timed mutexes currently */ +#define C11THREADS_NO_TIMED_MUTEX +#endif + +#ifdef C11THREADS_NO_TIMED_MUTEX +#define PTHREAD_MUTEX_TIMED_NP PTHREAD_MUTEX_NORMAL +#define C11THREADS_TIMEDLOCK_POLL_INTERVAL 5000000 /* 5 ms */ +#endif + +/* types */ +typedef pthread_t thrd_t; +typedef pthread_mutex_t mtx_t; +typedef pthread_cond_t cnd_t; +typedef pthread_key_t tss_t; +typedef pthread_once_t once_flag; + +typedef int (*thrd_start_t)(void*); +typedef void (*tss_dtor_t)(void*); + +enum { + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2, +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem +}; + + +/* ---- thread management ---- */ + +static inline int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + int res = pthread_create(thr, 0, (void*(*)(void*))func, arg); + if(res == 0) { + return thrd_success; + } + return res == ENOMEM ? thrd_nomem : thrd_error; +} + +static inline void thrd_exit(int res) +{ + pthread_exit((void*)(long)res); +} + +static inline int thrd_join(thrd_t thr, int *res) +{ + void *retval; + + if(pthread_join(thr, &retval) != 0) { + return thrd_error; + } + if(res) { + *res = (int)(long)retval; + } + return thrd_success; +} + +static inline int thrd_detach(thrd_t thr) +{ + return pthread_detach(thr) == 0 ? thrd_success : thrd_error; +} + +static inline thrd_t thrd_current(void) +{ + return pthread_self(); +} + +static inline int thrd_equal(thrd_t a, thrd_t b) +{ + return pthread_equal(a, b); +} + +static inline int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if(nanosleep(ts_in, rem_out) < 0) { + if(errno == EINTR) return -1; + return -2; + } + return 0; +} + +static inline void thrd_yield(void) +{ + sched_yield(); +} + +/* ---- mutexes ---- */ + +static inline int mtx_init(mtx_t *mtx, int type) +{ + int res; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + if(type & mtx_timed) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); + } + if(type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + + res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + pthread_mutexattr_destroy(&attr); + return res; +} + +static inline void mtx_destroy(mtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + +static inline int mtx_lock(mtx_t *mtx) +{ + int res = pthread_mutex_lock(mtx); + if(res == EDEADLK) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static inline int mtx_trylock(mtx_t *mtx) +{ + int res = pthread_mutex_trylock(mtx); + if(res == EBUSY) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static inline int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + int res; +#ifdef C11THREADS_NO_TIMED_MUTEX + /* fake a timedlock by polling trylock in a loop and waiting for a bit */ + struct timeval now; + struct timespec sleeptime; + + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = C11THREADS_TIMEDLOCK_POLL_INTERVAL; + + while((res = pthread_mutex_trylock(mtx)) == EBUSY) { + gettimeofday(&now, NULL); + + if(now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec && + (now.tv_usec * 1000) >= ts->tv_nsec)) { + return thrd_timedout; + } + + nanosleep(&sleeptime, NULL); + } +#else + if((res = pthread_mutex_timedlock(mtx, ts)) == ETIMEDOUT) { + return thrd_timedout; + } +#endif + return res == 0 ? thrd_success : thrd_error; +} + +static inline int mtx_unlock(mtx_t *mtx) +{ + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +/* ---- condition variables ---- */ + +static inline int cnd_init(cnd_t *cond) +{ + return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +static inline void cnd_destroy(cnd_t *cond) +{ + pthread_cond_destroy(cond); +} + +static inline int cnd_signal(cnd_t *cond) +{ + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +} + +static inline int cnd_broadcast(cnd_t *cond) +{ + return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +static inline int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +} + +static inline int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + int res; + + if((res = pthread_cond_timedwait(cond, mtx, ts)) != 0) { + return res == ETIMEDOUT ? thrd_timedout : thrd_error; + } + return thrd_success; +} + +/* ---- thread-specific data ---- */ + +static inline int tss_create(tss_t *key, tss_dtor_t dtor) +{ + return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error; +} + +static inline void tss_delete(tss_t key) +{ + pthread_key_delete(key); +} + +static inline int tss_set(tss_t key, void *val) +{ + return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error; +} + +static inline void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +/* ---- misc ---- */ + +static inline void call_once(once_flag *flag, void (*func)(void)) +{ + pthread_once(flag, func); +} + +#if __STDC_VERSION__ < 201112L || defined(C11THREADS_NO_TIMED_MUTEX) +/* TODO take base into account */ +static inline int timespec_get(struct timespec *ts, int base) +{ + struct timeval tv; + + gettimeofday(&tv, 0); + + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; +} +#endif /* not C11 */ + +#endif /* C11THREADS_H_ */ |