From 3ba4afd40b3ff43b406cfd6ea7b13958644b46d7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 12 Apr 2020 14:03:24 +0200 Subject: [PATCH] threads: make thread local storage manadatory Support either the __thread GNUism or the C11 _Thread_local. Use 'thread_local' to point to the one that is used. Convert existing __thread user to 'thread_local'. Remove non-thread-local code from the packet pool code. --- configure.ac | 32 +++++++++------ src/output-filestore.c | 2 +- src/suricata.c | 15 +++++-- src/threads-profile.h | 30 +++++++------- src/threads.h | 8 ++++ src/tm-threads.c | 24 +++++------ src/tmqh-packetpool.c | 74 +--------------------------------- src/util-profiling-keywords.c | 2 +- src/util-profiling-locks.c | 6 +-- src/util-profiling-prefilter.c | 2 +- src/util-profiling.c | 2 +- src/util-profiling.h | 6 +-- src/util-time.c | 18 ++++----- 13 files changed, 87 insertions(+), 134 deletions(-) diff --git a/configure.ac b/configure.ac index 71de01602a93..c65500e6221e 100644 --- a/configure.ac +++ b/configure.ac @@ -320,18 +320,26 @@ esac AC_MSG_RESULT(ok) - # disable TLS on user request - AC_ARG_ENABLE(threading-tls, - AS_HELP_STRING([--disable-threading-tls], [Disable TLS (thread local storage)]), [enable_tls="$enableval"],[enable_tls=yes]) - AS_IF([test "x$enable_tls" = "xyes"], [ - # check if our target supports thread local storage - AC_MSG_CHECKING(for thread local storage __thread support) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[ static __thread int i; i = 1; i++; ]])], - [AC_DEFINE([TLS], [1], [Thread local storage]) - AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([no])]) - ]) + # check if our target supports thread local storage + AC_MSG_CHECKING(for thread local storage c11 thread_local support) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ static _Thread_local int i; i = 1; i++; ]])], + [AC_DEFINE([TLS_C11], [1], [Thread local storage]) + AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + have_c11_tls=no]) + # check if our target supports thread local storage + AC_MSG_CHECKING(for thread local storage gnu __thread support) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ static __thread int i; i = 1; i++; ]])], + [AC_DEFINE([TLS_GNU], [1], [Thread local storage]) + AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + have_gnu_tls=no]) + if [ test "x$have_c11_tls" = "xno" ] && [ test "x$have_gnu_tls" = "xno" ]; then + AC_MSG_ERROR("no thread local support available.") + exit 1 + fi #Enable support for gcc compile time security options. There is no great way to do detection of valid cflags that I have found #AX_CFLAGS_GCC_OPTION don't seem to do a better job than the code below and are a pain because of extra m4 files etc. diff --git a/src/output-filestore.c b/src/output-filestore.c index e9c7f7131cfb..704053182798 100644 --- a/src/output-filestore.c +++ b/src/output-filestore.c @@ -63,7 +63,7 @@ typedef struct OutputFilestoreLogThread_ { /* For WARN_ONCE, a record of warnings that have already been * issued. */ -static __thread bool once_errs[SC_ERR_MAX]; +static thread_local bool once_errs[SC_ERR_MAX]; #define WARN_ONCE(err_code, ...) do { \ if (!once_errs[err_code]) { \ diff --git a/src/suricata.c b/src/suricata.c index a74d4065056d..f2376be30544 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -650,7 +650,7 @@ static void PrintBuildInfo(void) const char *bits = "-bits"; const char *endian = "-endian"; char features[2048] = ""; - const char *tls = "pthread key"; + const char *tls; printf("This is %s version %s\n", PROG_NAME, GetProgramVersion()); @@ -715,9 +715,14 @@ static void PrintBuildInfo(void) #ifdef PROFILE_LOCKING strlcat(features, "PROFILE_LOCKING ", sizeof(features)); #endif -#ifdef TLS +#if defined(TLS_C11) || defined(TLS_GNU) strlcat(features, "TLS ", sizeof(features)); #endif +#if defined(TLS_C11) + strlcat(features, "TLS_C11 ", sizeof(features)); +#elif defined(TLS_GNU) + strlcat(features, "TLS_GNU ", sizeof(features)); +#endif #ifdef HAVE_MAGIC strlcat(features, "MAGIC ", sizeof(features)); #endif @@ -810,8 +815,12 @@ static void PrintBuildInfo(void) #ifdef CLS printf("L1 cache line size (CLS)=%d\n", CLS); #endif -#ifdef TLS +#if defined(TLS_C11) + tls = "_Thread_local"; +#elif defined(TLS_GNU) tls = "__thread"; +#else +#error "Unsupported thread local" #endif printf("thread local storage method: %s\n", tls); diff --git a/src/threads-profile.h b/src/threads-profile.h index 6e19673b1048..1d66997f7d3a 100644 --- a/src/threads-profile.h +++ b/src/threads-profile.h @@ -37,13 +37,13 @@ typedef struct ProfilingLock_ { uint64_t ticks; } ProfilingLock; -extern __thread ProfilingLock locks[PROFILING_MAX_LOCKS]; -extern __thread int locks_idx; -extern __thread int record_locks; +extern thread_local ProfilingLock locks[PROFILING_MAX_LOCKS]; +extern thread_local int locks_idx; +extern thread_local int record_locks; -extern __thread uint64_t mutex_lock_contention; -extern __thread uint64_t mutex_lock_wait_ticks; -extern __thread uint64_t mutex_lock_cnt; +extern thread_local uint64_t mutex_lock_contention; +extern thread_local uint64_t mutex_lock_wait_ticks; +extern thread_local uint64_t mutex_lock_cnt; /* mutex */ @@ -92,9 +92,9 @@ extern __thread uint64_t mutex_lock_cnt; /* spinlocks */ -extern __thread uint64_t spin_lock_contention; -extern __thread uint64_t spin_lock_wait_ticks; -extern __thread uint64_t spin_lock_cnt; +extern thread_local uint64_t spin_lock_contention; +extern thread_local uint64_t spin_lock_wait_ticks; +extern thread_local uint64_t spin_lock_cnt; //printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); #define SCSpinLock_profile(spin) ({ \ @@ -131,9 +131,9 @@ extern __thread uint64_t spin_lock_cnt; /* rwlocks */ -extern __thread uint64_t rww_lock_contention; -extern __thread uint64_t rww_lock_wait_ticks; -extern __thread uint64_t rww_lock_cnt; +extern thread_local uint64_t rww_lock_contention; +extern thread_local uint64_t rww_lock_wait_ticks; +extern thread_local uint64_t rww_lock_cnt; #define SCRWLockWRLock_profile(mut) ({ \ rww_lock_cnt++; \ @@ -160,9 +160,9 @@ extern __thread uint64_t rww_lock_cnt; retl; \ }) -extern __thread uint64_t rwr_lock_contention; -extern __thread uint64_t rwr_lock_wait_ticks; -extern __thread uint64_t rwr_lock_cnt; +extern thread_local uint64_t rwr_lock_contention; +extern thread_local uint64_t rwr_lock_wait_ticks; +extern thread_local uint64_t rwr_lock_cnt; #define SCRWLockRDLock_profile(mut) ({ \ rwr_lock_cnt++; \ diff --git a/src/threads.h b/src/threads.h index 4eb1a73606da..17513cc5b40f 100644 --- a/src/threads.h +++ b/src/threads.h @@ -31,6 +31,14 @@ #include #endif +#if defined(TLS_C11) +#define thread_local _Thread_local +#elif defined(TLS_GNU) +#define thread_local __thread +#else +#error "No supported thread local type found" +#endif + /* need this for the _POSIX_SPIN_LOCKS define */ #if HAVE_UNISTD_H #include diff --git a/src/tm-threads.c b/src/tm-threads.c index b049b7ed6544..dd68b2feaf70 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -44,21 +44,21 @@ #include "queue.h" #ifdef PROFILE_LOCKING -__thread uint64_t mutex_lock_contention; -__thread uint64_t mutex_lock_wait_ticks; -__thread uint64_t mutex_lock_cnt; +thread_local uint64_t mutex_lock_contention; +thread_local uint64_t mutex_lock_wait_ticks; +thread_local uint64_t mutex_lock_cnt; -__thread uint64_t spin_lock_contention; -__thread uint64_t spin_lock_wait_ticks; -__thread uint64_t spin_lock_cnt; +thread_local uint64_t spin_lock_contention; +thread_local uint64_t spin_lock_wait_ticks; +thread_local uint64_t spin_lock_cnt; -__thread uint64_t rww_lock_contention; -__thread uint64_t rww_lock_wait_ticks; -__thread uint64_t rww_lock_cnt; +thread_local uint64_t rww_lock_contention; +thread_local uint64_t rww_lock_wait_ticks; +thread_local uint64_t rww_lock_cnt; -__thread uint64_t rwr_lock_contention; -__thread uint64_t rwr_lock_wait_ticks; -__thread uint64_t rwr_lock_cnt; +thread_local uint64_t rwr_lock_contention; +thread_local uint64_t rwr_lock_wait_ticks; +thread_local uint64_t rwr_lock_cnt; #endif #ifdef OS_FREEBSD diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index b8b963022347..ead8d0106ac5 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -54,76 +54,12 @@ #define MAX_PENDING_RETURN_PACKETS 32 static uint32_t max_pending_return_packets = MAX_PENDING_RETURN_PACKETS; -#ifdef TLS -__thread PktPool thread_pkt_pool; +thread_local PktPool thread_pkt_pool; static inline PktPool *GetThreadPacketPool(void) { return &thread_pkt_pool; } -#else -/* __thread not supported. */ -static pthread_key_t pkt_pool_thread_key; -static SCMutex pkt_pool_thread_key_mutex = SCMUTEX_INITIALIZER; -static int pkt_pool_thread_key_initialized = 0; - -static void PktPoolThreadDestroy(void * buf) -{ - SCFreeAligned(buf); -} - -static void TmqhPacketPoolInit(void) -{ - SCMutexLock(&pkt_pool_thread_key_mutex); - if (pkt_pool_thread_key_initialized) { - /* Key has already been created. */ - SCMutexUnlock(&pkt_pool_thread_key_mutex); - return; - } - - /* Create the pthread Key that is used to look up thread specific - * data buffer. Needs to be created only once. - */ - int r = pthread_key_create(&pkt_pool_thread_key, PktPoolThreadDestroy); - if (r != 0) { - SCLogError(SC_ERR_MEM_ALLOC, "pthread_key_create failed with %d", r); - exit(EXIT_FAILURE); - } - - pkt_pool_thread_key_initialized = 1; - SCMutexUnlock(&pkt_pool_thread_key_mutex); -} - -static PktPool *ThreadPacketPoolCreate(void) -{ - TmqhPacketPoolInit(); - - /* Create a new pool for this thread. */ - PktPool* pool = (PktPool*)SCMallocAligned(sizeof(PktPool), CLS); - if (pool == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "malloc failed"); - exit(EXIT_FAILURE); - } - memset(pool,0x0,sizeof(*pool)); - - int r = pthread_setspecific(pkt_pool_thread_key, pool); - if (r != 0) { - SCLogError(SC_ERR_MEM_ALLOC, "pthread_setspecific failed with %d", r); - exit(EXIT_FAILURE); - } - - return pool; -} - -static inline PktPool *GetThreadPacketPool(void) -{ - PktPool* pool = (PktPool*)pthread_getspecific(pkt_pool_thread_key); - if (pool == NULL) - pool = ThreadPacketPoolCreate(); - - return pool; -} -#endif /** * \brief TmqhPacketpoolRegister @@ -350,10 +286,6 @@ void PacketPoolReturnPacket(Packet *p) void PacketPoolInitEmpty(void) { -#ifndef TLS - TmqhPacketPoolInit(); -#endif - PktPool *my_pool = GetThreadPacketPool(); #ifdef DEBUG_VALIDATION @@ -371,10 +303,6 @@ void PacketPoolInit(void) { extern intmax_t max_pending_packets; -#ifndef TLS - TmqhPacketPoolInit(); -#endif - PktPool *my_pool = GetThreadPacketPool(); #ifdef DEBUG_VALIDATION diff --git a/src/util-profiling-keywords.c b/src/util-profiling-keywords.c index a96555451ff3..feee266d57e1 100644 --- a/src/util-profiling-keywords.c +++ b/src/util-profiling-keywords.c @@ -62,7 +62,7 @@ typedef struct SCProfileKeywordDetectCtx_ { static int profiling_keywords_output_to_file = 0; int profiling_keyword_enabled = 0; -__thread int profiling_keyword_entered = 0; +thread_local int profiling_keyword_entered = 0; static char profiling_file_name[PATH_MAX]; static const char *profiling_file_mode = "a"; diff --git a/src/util-profiling-locks.c b/src/util-profiling-locks.c index efbe9720fb26..084075059604 100644 --- a/src/util-profiling-locks.c +++ b/src/util-profiling-locks.c @@ -31,9 +31,9 @@ #ifdef PROFILING #ifdef PROFILE_LOCKING -__thread ProfilingLock locks[PROFILING_MAX_LOCKS]; -__thread int locks_idx = 0; -__thread int record_locks = 0; +thread_local ProfilingLock locks[PROFILING_MAX_LOCKS]; +thread_local int locks_idx = 0; +thread_local int record_locks = 0; int profiling_locks_enabled = 0; int profiling_locks_output_to_file = 0; diff --git a/src/util-profiling-prefilter.c b/src/util-profiling-prefilter.c index cb5e34e35339..bf8b38d99b11 100644 --- a/src/util-profiling-prefilter.c +++ b/src/util-profiling-prefilter.c @@ -56,7 +56,7 @@ typedef struct SCProfilePrefilterDetectCtx_ { static int profiling_prefilter_output_to_file = 0; int profiling_prefilter_enabled = 0; -__thread int profiling_prefilter_entered = 0; +thread_local int profiling_prefilter_entered = 0; static char profiling_file_name[PATH_MAX]; static const char *profiling_file_mode = "a"; diff --git a/src/util-profiling.c b/src/util-profiling.c index 7a590a557308..0fc1958ab8e2 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -114,7 +114,7 @@ static SC_ATOMIC_DECLARE(uint64_t, samples); /** * Used as a check so we don't double enter a profiling run. */ -__thread int profiling_rules_entered = 0; +thread_local int profiling_rules_entered = 0; void SCProfilingDumpPacketStats(void); const char * PacketProfileDetectIdToString(PacketProfileDetectId id); diff --git a/src/util-profiling.h b/src/util-profiling.h index 6ecdbdc145f7..ee0a88b5a5c3 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -33,7 +33,7 @@ extern int profiling_rules_enabled; extern int profiling_packets_enabled; extern int profiling_sghs_enabled; -extern __thread int profiling_rules_entered; +extern thread_local int profiling_rules_entered; void SCProfilingPrintPacketProfile(Packet *); void SCProfilingAddPacket(Packet *); @@ -60,7 +60,7 @@ int SCProfileRuleStart(Packet *p); } extern int profiling_keyword_enabled; -extern __thread int profiling_keyword_entered; +extern thread_local int profiling_keyword_entered; #define KEYWORD_PROFILING_SET_LIST(ctx, list) { \ (ctx)->keyword_perf_list = (list); \ @@ -275,7 +275,7 @@ PktProfiling *SCProfilePacketStart(void); } extern int profiling_prefilter_enabled; -extern __thread int profiling_prefilter_entered; +extern thread_local int profiling_prefilter_entered; #define PREFILTER_PROFILING_START \ uint64_t profile_prefilter_start_ = 0; \ diff --git a/src/util-time.c b/src/util-time.c index 2d63196e774a..71b9ca12c32b 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -242,7 +242,7 @@ struct tm *SCUtcTime(time_t timep, struct tm *result) */ #ifndef TLS -/* OpenBSD does not support __thread, so don't use time caching on BSD +/* OpenBSD does not support thread_local, so don't use time caching on BSD */ struct tm *SCLocalTime(time_t timep, struct tm *result) { @@ -266,7 +266,7 @@ void CreateTimeString (const struct timeval *ts, char *str, size_t size) #else -/* On systems supporting __thread, use Per-thread values for caching +/* On systems supporting thread_local, use Per-thread values for caching * in CreateTimeString */ /* The maximum possible length of the time string. @@ -274,16 +274,16 @@ void CreateTimeString (const struct timeval *ts, char *str, size_t size) * Or "01/01/2013-15:42:21.123456", which is 26, so round up to 32. */ #define MAX_LOCAL_TIME_STRING 32 -static __thread int mru_time_slot; /* Most recently used cached value */ -static __thread time_t last_local_time[2]; -static __thread short int cached_local_time_len[2]; -static __thread char cached_local_time[2][MAX_LOCAL_TIME_STRING]; +static thread_local int mru_time_slot; /* Most recently used cached value */ +static thread_local time_t last_local_time[2]; +static thread_local short int cached_local_time_len[2]; +static thread_local char cached_local_time[2][MAX_LOCAL_TIME_STRING]; /* Per-thread values for caching SCLocalTime() These cached values are * independent from the CreateTimeString cached values. */ -static __thread int mru_tm_slot; /* Most recently used local tm */ -static __thread time_t cached_minute_start[2]; -static __thread struct tm cached_local_tm[2]; +static thread_local int mru_tm_slot; /* Most recently used local tm */ +static thread_local time_t cached_minute_start[2]; +static thread_local struct tm cached_local_tm[2]; /** \brief Convert time_t into Year, month, day, hour and minutes. * \param timep Time in seconds since defined date.