diff --git a/Makefile.common b/Makefile.common index 76ed5fe6af..b04e7e22dc 100644 --- a/Makefile.common +++ b/Makefile.common @@ -575,6 +575,10 @@ ifeq ($(HAVE_THREADS), 1) endif endif +ifeq ($(HAVE_THREAD_STORAGE), 1) + DEFINES += -DHAVE_THREAD_STORAGE +endif + ifeq ($(HAVE_WAYLAND), 1) OBJ += gfx/drivers_context/wayland_ctx.o DEFINES += $(WAYLAND_CFLAGS) @@ -1064,7 +1068,7 @@ OBJ += $(ZLIB_OBJS) endif endif -# Video4Linux 2 +# Video4Linux 2 ifeq ($(HAVE_V4L2),1) OBJ += camera/drivers/video4linux2.o diff --git a/libretro-common/include/rthreads/rthreads.h b/libretro-common/include/rthreads/rthreads.h index a960d7f8ec..9af41fd301 100644 --- a/libretro-common/include/rthreads/rthreads.h +++ b/libretro-common/include/rthreads/rthreads.h @@ -36,6 +36,10 @@ typedef struct sthread sthread_t; typedef struct slock slock_t; typedef struct scond scond_t; +#ifdef HAVE_THREAD_STORAGE +typedef unsigned sthread_tls_t; +#endif + /** * sthread_create: * @start_routine : thread entry callback function @@ -178,6 +182,48 @@ int scond_broadcast(scond_t *cond); **/ void scond_signal(scond_t *cond); +#ifdef HAVE_THREAD_STORAGE +/** + * @brief Creates a thread local storage key + * + * This function shall create thread-specific data key visible to all threads in + * the process. The same key can be used by multiple threads to store + * thread-local data. + * + * When the key is created NULL shall be associated with it in all active + * threads. Whenever a new thread is spawned the all defined keys will be + * associated with NULL on that thread. + * + * @param tls + * @return whether the operation suceeded or not + */ +bool sthread_tls_create(sthread_tls_t *tls); + +/** + * @brief Deletes a thread local storage + * @param tls + * @return whether the operation suceeded or not + */ +bool sthread_tls_delete(sthread_tls_t *tls); + +/** + * @brief Retrieves thread specific data associated with a key + * + * There is no way to tell whether this function failed. + * + * @param tls + * @return + */ +void *sthread_tls_get(sthread_tls_t *tls); + +/** + * @brief Binds thread specific data to a key + * @param tls + * @return whether the operation suceeded or not + */ +bool sthread_tls_set(sthread_tls_t *tls, const void *data); +#endif + RETRO_END_DECLS #endif diff --git a/libretro-common/rthreads/rthreads.c b/libretro-common/rthreads/rthreads.c index 1c17d650b7..f8ea548be9 100644 --- a/libretro-common/rthreads/rthreads.c +++ b/libretro-common/rthreads/rthreads.c @@ -474,3 +474,41 @@ bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us) return (ret == 0); #endif } + +#ifdef HAVE_THREAD_STORAGE +bool sthread_tls_create(sthread_tls_t *tls) +{ +#ifdef USE_WIN32_THREADS + return (*tls = TlsAlloc()) != TLS_OUT_OF_INDEXES; +#else + return pthread_key_create(tls, NULL) == 0; +#endif +} + +bool sthread_tls_delete(sthread_tls_t *tls) +{ +#ifdef USE_WIN32_THREADS + return TlsFree(*tls) != 0; +#else + return pthread_key_delete(*tls) == 0; +#endif +} + +void *sthread_tls_get(sthread_tls_t *tls) +{ +#ifdef USE_WIN32_THREADS + return TlsGetValue(*tls); +#else + return pthread_getspecific(*tls); +#endif +} + +bool sthread_tls_set(sthread_tls_t *tls, const void *data) +{ +#ifdef USE_WIN32_THREADS + return TlsSetValue(*tls, (void*)data) != 0; +#else + return pthread_setspecific(*tls, data) == 0; +#endif +} +#endif diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 3cf24ece08..c60c9a0218 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -150,9 +150,17 @@ fi if [ "$OS" = 'Win32' ]; then HAVE_THREADS=yes + HAVE_THREAD_STORAGE=yes HAVE_DYLIB=yes else check_lib THREADS "$PTHREADLIB" pthread_create + + if [ "$HAVE_THREADS" = 'yes' ]; then + check_lib THREAD_STORAGE "$PTHREADLIB" pthread_key_create + else + HAVE_THREAD_STORAGE=no + fi + check_lib DYLIB "$DYLIB" dlopen fi diff --git a/qb/config.params.sh b/qb/config.params.sh index a5d1d57481..61d5a41861 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -1,6 +1,6 @@ HAVE_LIBRETRODB=yes # Libretrodb support HAVE_RGUI=yes # RGUI menu -HAVE_MATERIALUI=auto # MaterialUI menu +HAVE_MATERIALUI=auto # MaterialUI menu HAVE_XMB=auto # XMB menu HAVE_ZARCH=no # Zarch menu HAVE_NUKLEAR=no # Nuklear menu @@ -20,6 +20,7 @@ HAVE_MAN_DIR= # Manpage install directory HAVE_OPENGLES_LIBS= # Link flags for custom GLES library HAVE_OPENGLES_CFLAGS= # C-flags for custom GLES library HAVE_THREADS=auto # Threading support +HAVE_THREAD_STORAGE=auto # Thread Local Storage support HAVE_FFMPEG=auto # FFmpeg recording support C89_FFMPEG=no HAVE_SSA=auto # SSA/ASS for FFmpeg subtitle support diff --git a/retroarch.c b/retroarch.c index f544a67ff2..2c8effecb5 100644 --- a/retroarch.c +++ b/retroarch.c @@ -42,7 +42,7 @@ #include #include #include - +#include #include #ifdef HAVE_CONFIG_H @@ -1108,6 +1108,10 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) static bool rarch_ips_pref = false; static bool rarch_patch_blocked = false; settings_t *settings = config_get_ptr(); +#ifdef HAVE_THREAD_STORAGE + static sthread_tls_t rarch_tls; + const void *MAGIC_POINTER = (void*)0xB16B00B5; +#endif switch(state) { @@ -1218,9 +1222,17 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) path_deinit_savefile(); rarch_ctl(RARCH_CTL_UNSET_INITED, NULL); + +#ifdef HAVE_THREAD_STORAGE + sthread_tls_delete(&rarch_tls); +#endif break; case RARCH_CTL_INIT: rarch_ctl(RARCH_CTL_DEINIT, NULL); +#ifdef HAVE_THREAD_STORAGE + sthread_tls_create(&rarch_tls); + sthread_tls_set(&rarch_tls, MAGIC_POINTER); +#endif retroarch_init_state(); { unsigned i; @@ -1306,6 +1318,12 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) command_event(CMD_EVENT_OVERLAY_INIT, NULL); #endif break; + case RARCH_CTL_IS_MAIN_THREAD: +#ifdef HAVE_THREAD_STORAGE + return sthread_tls_get(&rarch_tls) == MAGIC_POINTER; +#else + return true; +#endif case RARCH_CTL_NONE: default: return false; diff --git a/retroarch.h b/retroarch.h index e8fb374033..15799c69fd 100644 --- a/retroarch.h +++ b/retroarch.h @@ -106,8 +106,9 @@ enum rarch_ctl_state /* Username */ RARCH_CTL_HAS_SET_USERNAME, RARCH_CTL_USERNAME_SET, - RARCH_CTL_USERNAME_UNSET + RARCH_CTL_USERNAME_UNSET, + RARCH_CTL_IS_MAIN_THREAD }; enum rarch_capabilities