From cc4a483286c53a73d64eb134de0d2214f1e9d282 Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Sun, 14 Jan 2024 20:52:28 +0100 Subject: [PATCH 1/9] Make dlopen cross platform `__mcx_dll_load()` makes use of the function `dlopen()`, which has a flag parameter. On Linux one uses `RTLD_DEEPBIND` to ensure that a library uses its own symbols rather than those provided by other loaded libraries. On MacOS there is not a direct equivalent available. Signed-off-by: Robin Caloudis --- libs/util/CMakeLists.txt | 8 ++++---- libs/util/src/{linux => unix}/libs.c | 11 +++++++++-- libs/util/src/{linux => unix}/os.c | 0 libs/util/src/{linux => unix}/paths.c | 0 libs/util/src/{linux => unix}/string.c | 0 5 files changed, 13 insertions(+), 6 deletions(-) rename libs/util/src/{linux => unix}/libs.c (87%) rename libs/util/src/{linux => unix}/os.c (100%) rename libs/util/src/{linux => unix}/paths.c (100%) rename libs/util/src/{linux => unix}/string.c (100%) diff --git a/libs/util/CMakeLists.txt b/libs/util/CMakeLists.txt index e8254b8..72f06de 100644 --- a/libs/util/CMakeLists.txt +++ b/libs/util/CMakeLists.txt @@ -28,10 +28,10 @@ if(WIN32) ) else() set(UTIL_PLATFORM_SOURCES - "${CMAKE_CURRENT_SOURCE_DIR}/src/linux/libs.c" - "${CMAKE_CURRENT_SOURCE_DIR}/src/linux/os.c" - "${CMAKE_CURRENT_SOURCE_DIR}/src/linux/paths.c" - "${CMAKE_CURRENT_SOURCE_DIR}/src/linux/string.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/unix/libs.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/unix/os.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/unix/paths.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/unix/string.c" ) endif() diff --git a/libs/util/src/linux/libs.c b/libs/util/src/unix/libs.c similarity index 87% rename from libs/util/src/linux/libs.c rename to libs/util/src/unix/libs.c index efe7c2c..89733af 100644 --- a/libs/util/src/linux/libs.c +++ b/libs/util/src/unix/libs.c @@ -31,13 +31,20 @@ static McxStatus __mcx_dll_load(DllHandle * handle, const char * dllPath, int fl return RETURN_OK; } - McxStatus mcx_dll_load(DllHandle * handle, const char * dllPath) { +#if(__APPLE__) + return __mcx_dll_load(handle, dllPath, RTLD_LAZY|RTLD_LOCAL); +#else return __mcx_dll_load(handle, dllPath, RTLD_LAZY|RTLD_LOCAL|RTLD_DEEPBIND); +#endif } McxStatus mcx_dll_load_global(DllHandle * handle, const char * dllPath) { +#if(__APPLE__) + return __mcx_dll_load(handle, dllPath, RTLD_LAZY|RTLD_GLOBAL); +#else return __mcx_dll_load(handle, dllPath, RTLD_LAZY|RTLD_GLOBAL|RTLD_DEEPBIND); +#endif } void * mcx_dll_get_function(DllHandle dllHandle, const char* functionName) { @@ -55,4 +62,4 @@ void mcx_dll_free(DllHandle dllHandle) #ifdef __cplusplus } /* closing brace for extern "C" */ -#endif /* __cplusplus */ \ No newline at end of file +#endif /* __cplusplus */ diff --git a/libs/util/src/linux/os.c b/libs/util/src/unix/os.c similarity index 100% rename from libs/util/src/linux/os.c rename to libs/util/src/unix/os.c diff --git a/libs/util/src/linux/paths.c b/libs/util/src/unix/paths.c similarity index 100% rename from libs/util/src/linux/paths.c rename to libs/util/src/unix/paths.c diff --git a/libs/util/src/linux/string.c b/libs/util/src/unix/string.c similarity index 100% rename from libs/util/src/linux/string.c rename to libs/util/src/unix/string.c From 255b04cc2eb02eaab391fc8c1d2069d62b6b6bf9 Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Sun, 14 Jan 2024 21:25:47 +0100 Subject: [PATCH 2/9] Provide portable impl of pthread_timedjoin_np Signed-off-by: Robin Caloudis --- src/CMakeLists.txt | 2 +- src/util/{linux => unix}/events.c | 0 src/util/{linux => unix}/mutex.c | 0 src/util/{linux => unix}/signals.c | 0 src/util/{linux => unix}/socket.c | 0 src/util/{linux => unix}/stdlib.c | 0 src/util/{linux => unix}/threads.c | 62 +++++++++++++++++++++++++++++- src/util/{linux => unix}/time.c | 0 8 files changed, 61 insertions(+), 3 deletions(-) rename src/util/{linux => unix}/events.c (100%) rename src/util/{linux => unix}/mutex.c (100%) rename src/util/{linux => unix}/signals.c (100%) rename src/util/{linux => unix}/socket.c (100%) rename src/util/{linux => unix}/stdlib.c (100%) rename src/util/{linux => unix}/threads.c (56%) rename src/util/{linux => unix}/time.c (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2de6bcc..8ff5358 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,7 +43,7 @@ file(GLOB UTIL_HEADERS "util/*.h") if(WIN32) file(GLOB UTIL_SRC "util/win/*.c" "util/*.c" "util/common/*.c") else() - file(GLOB UTIL_SRC "util/linux/*.c" "util/*.c" "util/common/*.c") + file(GLOB UTIL_SRC "util/unix/*.c" "util/*.c" "util/common/*.c") endif() diff --git a/src/util/linux/events.c b/src/util/unix/events.c similarity index 100% rename from src/util/linux/events.c rename to src/util/unix/events.c diff --git a/src/util/linux/mutex.c b/src/util/unix/mutex.c similarity index 100% rename from src/util/linux/mutex.c rename to src/util/unix/mutex.c diff --git a/src/util/linux/signals.c b/src/util/unix/signals.c similarity index 100% rename from src/util/linux/signals.c rename to src/util/unix/signals.c diff --git a/src/util/linux/socket.c b/src/util/unix/socket.c similarity index 100% rename from src/util/linux/socket.c rename to src/util/unix/socket.c diff --git a/src/util/linux/stdlib.c b/src/util/unix/stdlib.c similarity index 100% rename from src/util/linux/stdlib.c rename to src/util/unix/stdlib.c diff --git a/src/util/linux/threads.c b/src/util/unix/threads.c similarity index 56% rename from src/util/linux/threads.c rename to src/util/unix/threads.c index 434cad1..d5672f7 100644 --- a/src/util/linux/threads.c +++ b/src/util/unix/threads.c @@ -44,6 +44,64 @@ int mcx_thread_join(McxThread handle, long * ret) { return pthread_join(handle, (void * *) ret); } +struct args { + int joined; + pthread_t td; + pthread_mutex_t mtx; + pthread_cond_t cond; + void **res; +}; + +static void *waiter(void *ap) +{ + struct args *args = ap; + pthread_join(args->td, args->res); + pthread_mutex_lock(&args->mtx); + args->joined = 1; + pthread_mutex_unlock(&args->mtx); + pthread_cond_signal(&args->cond); + return 0; +} + +// Portable implementation of `pthread_timedjoin_np()`. Inspired +// and copied from https://stackoverflow.com/a/11552244. As this +// implementation is more costly than `pthread_timedjoin_np()`, +// we only use this portable version for Apple platforms. +int pthread_timedjoin_p(pthread_t td, void **res, struct timespec *ts) +{ + pthread_t tmp; + int ret; + struct args args = { .td = td, .res = res }; + + pthread_mutex_init(&args.mtx, 0); + pthread_cond_init(&args.cond, 0); + pthread_mutex_lock(&args.mtx); + + ret = pthread_create(&tmp, 0, waiter, &args); + if (!ret) + do ret = pthread_cond_timedwait(&args.cond, &args.mtx, ts); + while (!args.joined && ret != ETIMEDOUT); + + pthread_mutex_unlock(&args.mtx); + + pthread_cancel(tmp); + pthread_join(tmp, 0); + + pthread_cond_destroy(&args.cond); + pthread_mutex_destroy(&args.mtx); + + return args.joined ? 0 : ret; +} + +int pthread_timedjoin(pthread_t handle, void **ret, struct timespec *time) +{ +#if(__APPLE__) + return pthread_timedjoin_p(handle, ret, time); +#else + return pthread_timedjoin_np(handle, ret, time); +#endif +} + int mcx_thread_join_with_timeout(McxThread handle, long * ret, int secs) { struct timespec time; int status = 0; @@ -53,7 +111,7 @@ int mcx_thread_join_with_timeout(McxThread handle, long * ret, int secs) { time.tv_sec += secs; - status = pthread_timedjoin_np(handle, (void * *) ret, &time); + status = pthread_timedjoin(handle, (void * *) ret, &time); if (status) { const char * cause = NULL; @@ -79,4 +137,4 @@ int mcx_thread_join_with_timeout(McxThread handle, long * ret, int secs) { } /* closing brace for extern "C" */ #endif /* __cplusplus */ -#endif // ENABLE_MT \ No newline at end of file +#endif // ENABLE_MT diff --git a/src/util/linux/time.c b/src/util/unix/time.c similarity index 100% rename from src/util/linux/time.c rename to src/util/unix/time.c From 46f64edc20d562ea6ad85be6ffd7ed5d18987c79 Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Sun, 14 Jan 2024 21:33:22 +0100 Subject: [PATCH 3/9] Do not use Linux specific link options on Mac OS Signed-off-by: Robin Caloudis --- mcx/CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mcx/CMakeLists.txt b/mcx/CMakeLists.txt index 3d6957c..5d93ce5 100644 --- a/mcx/CMakeLists.txt +++ b/mcx/CMakeLists.txt @@ -20,7 +20,7 @@ target_link_libraries(${EXECUTABLE_NAME} PRIVATE mcx_common) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/" PREFIX "Source Files" FILES ${MCX_EXE_SOURCES}) -if(UNIX) +if(UNIX AND NOT APPLE) set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_OPTIONS -Wl,--exclude-libs,ALL) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ff5358..732cb75 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,7 +94,7 @@ target_compile_definitions( ) -if(UNIX) +if(UNIX AND NOT APPLE) set_target_properties(mcx_common PROPERTIES LINK_OPTIONS -Wl,--exclude-libs,ALL) endif() From c0a000fcda232160131f0401b9f02a21bf5190a3 Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Sun, 14 Jan 2024 21:34:58 +0100 Subject: [PATCH 4/9] Provide platform independent fmu's Signed-off-by: Robin Caloudis --- fmus/gain/CMakeLists.txt | 3 +++ fmus/sinusGenerator/CMakeLists.txt | 3 +++ fmus/vectorSum/CMakeLists.txt | 3 +++ 3 files changed, 9 insertions(+) diff --git a/fmus/gain/CMakeLists.txt b/fmus/gain/CMakeLists.txt index 1ae28d1..84cc091 100644 --- a/fmus/gain/CMakeLists.txt +++ b/fmus/gain/CMakeLists.txt @@ -9,6 +9,9 @@ project(${FMU_NAME}) if(WIN32) set(FMU_PLATFORM win) set(FMU_SO_SUFFIX ".dll") +elseif(APPLE) + set(FMU_PLATFORM darwin) + set(FMU_SO_SUFFIX ".dylib") elseif(UNIX) set(FMU_PLATFORM linux) set(FMU_SO_SUFFIX ".so") diff --git a/fmus/sinusGenerator/CMakeLists.txt b/fmus/sinusGenerator/CMakeLists.txt index 3ae058c..072a4ad 100644 --- a/fmus/sinusGenerator/CMakeLists.txt +++ b/fmus/sinusGenerator/CMakeLists.txt @@ -9,6 +9,9 @@ project(${FMU_NAME}) if(WIN32) set(FMU_PLATFORM win) set(FMU_SO_SUFFIX ".dll") +elseif(APPLE) + set(FMU_PLATFORM darwin) + set(FMU_SO_SUFFIX ".dylib") elseif(UNIX) set(FMU_PLATFORM linux) set(FMU_SO_SUFFIX ".so") diff --git a/fmus/vectorSum/CMakeLists.txt b/fmus/vectorSum/CMakeLists.txt index 0979314..8b20887 100644 --- a/fmus/vectorSum/CMakeLists.txt +++ b/fmus/vectorSum/CMakeLists.txt @@ -9,6 +9,9 @@ project(${FMU_NAME}) if(WIN32) set(FMU_PLATFORM win) set(FMU_SO_SUFFIX ".dll") +elseif(APPLE) + set(FMU_PLATFORM darwin) + set(FMU_SO_SUFFIX ".dylib") elseif(UNIX) set(FMU_PLATFORM linux) set(FMU_SO_SUFFIX ".so") From 11a55fc4c1ec65741b3adf26b68c991524bd8fb8 Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Sun, 14 Jan 2024 22:11:55 +0100 Subject: [PATCH 5/9] Make `mcx_sort()` portable Signed-off-by: Robin Caloudis --- src/objects/ObjectContainer.c | 10 ++++++++-- src/util/stdlib.h | 8 +++++++- src/util/unix/stdlib.c | 10 +++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/objects/ObjectContainer.c b/src/objects/ObjectContainer.c index 610d724..f73069e 100644 --- a/src/objects/ObjectContainer.c +++ b/src/objects/ObjectContainer.c @@ -82,8 +82,14 @@ typedef struct { void * arg; } StrCmpCtx; -static int ObjectContainerElementCmp(const void * first, const void * second, void * ctx) { - StrCmpCtx * data = (StrCmpCtx *)ctx; +#if(__APPLE__) +static int ObjectContainerElementCmp(void *ctx, const void *first, + const void *second) { +#else +static int ObjectContainerElementCmp(const void * first, const void * second, + void * ctx) { +#endif + StrCmpCtx *data = (StrCmpCtx *)ctx; ObjectContainerElement * firstElement = (ObjectContainerElement *) first; ObjectContainerElement * secondElement = (ObjectContainerElement *) second; diff --git a/src/util/stdlib.h b/src/util/stdlib.h index 52332c2..2760a31 100644 --- a/src/util/stdlib.h +++ b/src/util/stdlib.h @@ -32,8 +32,14 @@ extern "C" { * is the context passed to mcx_sort. * @param arg context for the compar function */ -void mcx_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg); +#if(__APPLE__) +void mcx_sort(void *base, size_t nmemb, size_t size, + int (*compar)(void *, const void *, const void *), void *arg); +#else +void mcx_sort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *, void *), void *arg); +#endif int mcx_natural_sort_cmp(const char * left, const char * right); /** diff --git a/src/util/unix/stdlib.c b/src/util/unix/stdlib.c index ef36f9f..f8795de 100644 --- a/src/util/unix/stdlib.c +++ b/src/util/unix/stdlib.c @@ -19,9 +19,17 @@ extern "C" { #endif /* __cplusplus */ -void mcx_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg) { +#if (__APPLE__) +void mcx_sort(void *base, size_t nmemb, size_t size, + int (*compar)(void *, const void *, const void *), void *arg) { + qsort_r(base, nmemb, size, arg, compar); +} +#else +void mcx_sort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *, void *), void *arg) { qsort_r(base, nmemb, size, compar, arg); } +#endif #ifdef __cplusplus From 339f1f87bc0d8802a04ee233d081fb6749ea3a4e Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Sun, 14 Jan 2024 22:16:30 +0100 Subject: [PATCH 6/9] Include necessary headers for Apple platform When openmcx gets compiled on a Apple machine, it requires two additional headers to be present. My assumption is that these headers find its way into the compilation unit transitively on Linux and Windows machines, which they do not on Apple machines. Signed-off-by: Robin Caloudis --- src/util/mutex.h | 3 ++- src/util/threads.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util/mutex.h b/src/util/mutex.h index fbaea8e..3e0e9d9 100644 --- a/src/util/mutex.h +++ b/src/util/mutex.h @@ -11,8 +11,9 @@ #ifndef MCX_UTIL_MUTEX_H #define MCX_UTIL_MUTEX_H -#include "CentralParts.h" +#include "sys/types.h" +#include "CentralParts.h" #if defined (ENABLE_MT) #ifdef __cplusplus diff --git a/src/util/threads.h b/src/util/threads.h index 8bf9d1e..4d2fa4e 100644 --- a/src/util/threads.h +++ b/src/util/threads.h @@ -20,7 +20,7 @@ extern "C" { #endif /* __cplusplus */ #include - +#include #if defined(OS_WINDOWS) #define _WINSOCKAPI_ // stops windows.h including winsock.h #include From 2fb3e2442eeb0dd258cb5856e01a2e375e01266a Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Sun, 14 Jan 2024 23:16:48 +0100 Subject: [PATCH 7/9] Guard headers that are only used on Apple machines Signed-off-by: Robin Caloudis --- src/objects/ObjectContainer.c | 2 +- src/util/mutex.h | 2 ++ src/util/stdlib.h | 2 +- src/util/threads.h | 4 ++++ src/util/unix/stdlib.c | 4 ++-- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/objects/ObjectContainer.c b/src/objects/ObjectContainer.c index f73069e..58f2db7 100644 --- a/src/objects/ObjectContainer.c +++ b/src/objects/ObjectContainer.c @@ -87,7 +87,7 @@ static int ObjectContainerElementCmp(void *ctx, const void *first, const void *second) { #else static int ObjectContainerElementCmp(const void * first, const void * second, - void * ctx) { + void * ctx) { #endif StrCmpCtx *data = (StrCmpCtx *)ctx; diff --git a/src/util/mutex.h b/src/util/mutex.h index 3e0e9d9..41960c2 100644 --- a/src/util/mutex.h +++ b/src/util/mutex.h @@ -11,7 +11,9 @@ #ifndef MCX_UTIL_MUTEX_H #define MCX_UTIL_MUTEX_H +#if(__APPLE__) #include "sys/types.h" +#endif #include "CentralParts.h" #if defined (ENABLE_MT) diff --git a/src/util/stdlib.h b/src/util/stdlib.h index 2760a31..55a1764 100644 --- a/src/util/stdlib.h +++ b/src/util/stdlib.h @@ -38,7 +38,7 @@ void mcx_sort(void *base, size_t nmemb, size_t size, int (*compar)(void *, const void *, const void *), void *arg); #else void mcx_sort(void *base, size_t nmemb, size_t size, - int (*compar)(const void *, const void *, void *), void *arg); + int (*compar)(const void *, const void *, void *), void *arg); #endif int mcx_natural_sort_cmp(const char * left, const char * right); diff --git a/src/util/threads.h b/src/util/threads.h index 4d2fa4e..d8ffc34 100644 --- a/src/util/threads.h +++ b/src/util/threads.h @@ -20,7 +20,11 @@ extern "C" { #endif /* __cplusplus */ #include + +#if(__APPLE__) #include +#endif + #if defined(OS_WINDOWS) #define _WINSOCKAPI_ // stops windows.h including winsock.h #include diff --git a/src/util/unix/stdlib.c b/src/util/unix/stdlib.c index f8795de..e66d3fe 100644 --- a/src/util/unix/stdlib.c +++ b/src/util/unix/stdlib.c @@ -26,8 +26,8 @@ void mcx_sort(void *base, size_t nmemb, size_t size, } #else void mcx_sort(void *base, size_t nmemb, size_t size, - int (*compar)(const void *, const void *, void *), void *arg) { - qsort_r(base, nmemb, size, compar, arg); + int (*compar)(const void *, const void *, void *), void *arg) { + qsort_r(base, nmemb, size, compar, arg); } #endif From dcfc116123fede67726596d8d178b66a4ba2a183 Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Tue, 6 Feb 2024 17:57:45 +0100 Subject: [PATCH 8/9] Add comment about differences in qsort_r --- src/util/unix/stdlib.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util/unix/stdlib.c b/src/util/unix/stdlib.c index e66d3fe..69d7068 100644 --- a/src/util/unix/stdlib.c +++ b/src/util/unix/stdlib.c @@ -22,6 +22,12 @@ extern "C" { #if (__APPLE__) void mcx_sort(void *base, size_t nmemb, size_t size, int (*compar)(void *, const void *, const void *), void *arg) { + // FreeBSD added qsort_r in Sept 2002, but with a poor interface. In + // 2008 GNU fixed the interface and decided the compatibility breakage + // was worth it following ISO. Linux is GNU. OS X is a mish-mash of many + // things, but for C it follows BSD. As a result, we have difference in + // the non-standard qsort_r function. + // See https://stackoverflow.com/a/39561369 for details. qsort_r(base, nmemb, size, arg, compar); } #else From 7edbe232b28ee24734de8decb81c30b34bc7cc96 Mon Sep 17 00:00:00 2001 From: Robin Caloudis Date: Tue, 6 Feb 2024 18:06:22 +0100 Subject: [PATCH 9/9] Bracket the code properly --- src/util/unix/threads.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/util/unix/threads.c b/src/util/unix/threads.c index d5672f7..2c9f6aa 100644 --- a/src/util/unix/threads.c +++ b/src/util/unix/threads.c @@ -78,9 +78,11 @@ int pthread_timedjoin_p(pthread_t td, void **res, struct timespec *ts) pthread_mutex_lock(&args.mtx); ret = pthread_create(&tmp, 0, waiter, &args); - if (!ret) - do ret = pthread_cond_timedwait(&args.cond, &args.mtx, ts); - while (!args.joined && ret != ETIMEDOUT); + if (!ret) { + do { + ret = pthread_cond_timedwait(&args.cond, &args.mtx, ts); + } while (!args.joined && ret != ETIMEDOUT); + } pthread_mutex_unlock(&args.mtx);