summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Minichmayr <markus@tapkey.com>2022-10-10 19:01:06 +0200
committerAllen Winter <allen.winter@kdab.com>2022-11-22 05:12:15 -0500
commit108c485248f28557cd864dd13da9acd510758620 (patch)
tree761bfde85219d24452fc2151a652a87bea5b68e0
parent2fdae45ec8f231bb418238f20556da2ad54d9d17 (diff)
downloadlibical-git-108c485248f28557cd864dd13da9acd510758620.tar.gz
CMAKE option LIBICAL_SYNC_MODE_THREADLOCAL: Allow compiling all global variables with thread-local storage, thus avoiding the need for synchronization.
-rw-r--r--CMakeLists.txt10
-rw-r--r--config.h.cmake31
-rw-r--r--src/libical/icalerror.c2
-rw-r--r--src/libical/icalmemory.c10
-rw-r--r--src/libical/icalmemory.h4
-rw-r--r--src/libical/icalrecur.c10
-rw-r--r--src/libical/icaltimezone.c10
-rw-r--r--src/libical/icaltypes.c10
-rw-r--r--src/libical/pvl.c2
-rw-r--r--src/test/builtin_timezones.c6
-rw-r--r--src/test/icaltm_test.c14
11 files changed, 81 insertions, 28 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f5d5e52c..c568dd0b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -107,6 +107,13 @@
# Build with the undefined sanitizer (requires gcc or clang)
# Default=false
#
+# -DLIBICAL_SYNCMODE_THREADLOCAL=[true|false]
+# Experimental: If set to true, global variables are marked as thread-local. This allows accessing
+# libical from multiple threads without the need for synchronization. However, any global settings
+# must be applied per thread.
+# If set to false, the default synchronization mechanism is applied. That is, if the pthreads library
+# is available, it will be used, otherwise no synchronization is applied.
+# Default: false.
cmake_minimum_required(VERSION 3.11.0) #first line, to shutup a cygwin warning
project(libical C) #CXX is optional for the bindings
@@ -736,6 +743,9 @@ if(LIBICAL_DEVMODE_UNDEFINED_SANITIZER)
endif()
endif()
+mark_as_advanced(LIBICAL_SYNCMODE_THREADLOCAL)
+libical_option(LIBICAL_SYNCMODE_THREADLOCAL "Experimental: Mark global variables as thread-local." False)
+
libical_option(ENABLE_LTO_BUILD "Build a link-time optimized version." False)
if(ENABLE_LTO_BUILD)
if(CMAKE_C_COMPILER_IS_GCC)
diff --git a/config.h.cmake b/config.h.cmake
index 0e7306cc..93ac378d 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -583,5 +583,34 @@ typedef ssize_t IO_SSIZE_T;
#define ICALMEMORY_DEFAULT_REALLOC realloc
#define ICALMEMORY_DEFAULT_FREE free
-/* ICAL_GLOBAL_VAR is applied to global variables, therefore allows specifying custom storage attributes. */
+
+#cmakedefine LIBICAL_SYNCMODE_THREADLOCAL 1
+
+#define ICAL_SYNC_MODE_NONE 1
+#define ICAL_SYNC_MODE_PTHREAD 2
+#define ICAL_SYNC_MODE_THREADLOCAL 3
+
+#ifdef LIBICAL_SYNCMODE_THREADLOCAL
+#define ICAL_SYNC_MODE ICAL_SYNC_MODE_THREADLOCAL
+#elif HAVE_PTHREAD == 1
+#define ICAL_SYNC_MODE ICAL_SYNC_MODE_PTHREAD
+#else
+#define ICAL_SYNC_MODE ICAL_SYNC_MODE_NONE
+#endif
+
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_THREADLOCAL
+#if defined(_MSC_VER)
+#define ICAL_GLOBAL_VAR __declspec(thread)
+#endif
+#if defined(__GNUC__)
+#define ICAL_GLOBAL_VAR __thread
+#endif
+#ifndef ICAL_GLOBAL_VAR
+/* thread_local has been introduced with C11. Starting with C23 it will become a keyword and
+ we won't need to include threads.h then. */
+#include <threads.h>
+#define ICAL_GLOBAL_VAR thread_local
+#endif
+#else
#define ICAL_GLOBAL_VAR
+#endif
diff --git a/src/libical/icalerror.c b/src/libical/icalerror.c
index 9692bd1e..d8a85b4c 100644
--- a/src/libical/icalerror.c
+++ b/src/libical/icalerror.c
@@ -22,7 +22,7 @@
#include <execinfo.h>
#endif
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
#include <pthread.h>
static pthread_key_t icalerrno_key;
diff --git a/src/libical/icalmemory.c b/src/libical/icalmemory.c
index f12833b3..abf98618 100644
--- a/src/libical/icalmemory.c
+++ b/src/libical/icalmemory.c
@@ -39,7 +39,7 @@ typedef struct
void *ring[BUFFER_RING_SIZE];
} buffer_ring;
-#if !defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE != ICAL_SYNC_MODE_PTHREAD
/**
* @private
*/
@@ -63,7 +63,7 @@ static void icalmemory_free_ring_byval(buffer_ring * br)
icalmemory_free_buffer(br);
}
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
#include <pthread.h>
static pthread_key_t ring_key;
@@ -116,7 +116,7 @@ static buffer_ring *buffer_ring_new(void)
return (br);
}
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
/**
* @private
*/
@@ -156,7 +156,7 @@ static buffer_ring *get_buffer_ring_global(void)
*/
static buffer_ring *get_buffer_ring(void)
{
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
return (get_buffer_ring_pthread());
#else
return get_buffer_ring_global();
@@ -221,7 +221,7 @@ void icalmemory_free_ring(void)
return;
icalmemory_free_ring_byval(br);
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_setspecific(ring_key, 0);
#else
global_buffer_ring = 0;
diff --git a/src/libical/icalmemory.h b/src/libical/icalmemory.h
index 39541d2d..adb580da 100644
--- a/src/libical/icalmemory.h
+++ b/src/libical/icalmemory.h
@@ -120,8 +120,8 @@ LIBICAL_ICAL_EXPORT void icalmemory_add_tmp_buffer(void *buf);
/**
* @brief Frees all memory used in the ring
*
- * Frees all memory used in the ring. Depending on if HAVE_PTHREAD is set or
- * not, the ring buffer is allocated on a per-thread basis, meaning that if all
+ * Frees all memory used in the ring. If PTHREAD is used or thread-local mode is configured,
+ * the ring buffer is allocated on a per-thread basis, meaning that if all
* rings are to be released, it must be called once in every thread.
*
* @par Usage
diff --git a/src/libical/icalrecur.c b/src/libical/icalrecur.c
index b9c7b77d..6080bea5 100644
--- a/src/libical/icalrecur.c
+++ b/src/libical/icalrecur.c
@@ -134,7 +134,7 @@
#include <stddef.h> /* For offsetof() macro */
#include <stdlib.h>
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
#include <pthread.h>
static pthread_mutex_t invalid_rrule_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
@@ -3642,13 +3642,13 @@ ical_invalid_rrule_handling ical_get_invalid_rrule_handling_setting(void)
{
ical_invalid_rrule_handling myHandling;
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_lock(&invalid_rrule_mutex);
#endif
myHandling = invalidRruleHandling;
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_unlock(&invalid_rrule_mutex);
#endif
@@ -3657,13 +3657,13 @@ ical_invalid_rrule_handling ical_get_invalid_rrule_handling_setting(void)
void ical_set_invalid_rrule_handling_setting(ical_invalid_rrule_handling newSetting)
{
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_lock(&invalid_rrule_mutex);
#endif
invalidRruleHandling = newSetting;
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_unlock(&invalid_rrule_mutex);
#endif
}
diff --git a/src/libical/icaltimezone.c b/src/libical/icaltimezone.c
index 60b26a0d..acaf39c2 100644
--- a/src/libical/icaltimezone.c
+++ b/src/libical/icaltimezone.c
@@ -26,7 +26,7 @@
#include <stdlib.h>
#include <limits.h>
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
#include <pthread.h>
#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
// It seems the same thread can attempt to lock builtin_mutex multiple times
@@ -166,28 +166,28 @@ static const char *get_zone_directory(void);
static void icaltimezone_builtin_lock(void)
{
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_lock(&builtin_mutex);
#endif
}
static void icaltimezone_builtin_unlock(void)
{
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_unlock(&builtin_mutex);
#endif
}
static void icaltimezone_changes_lock(void)
{
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_lock(&changes_mutex);
#endif
}
static void icaltimezone_changes_unlock(void)
{
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_unlock(&changes_mutex);
#endif
}
diff --git a/src/libical/icaltypes.c b/src/libical/icaltypes.c
index 95d18540..ad85ae52 100644
--- a/src/libical/icaltypes.c
+++ b/src/libical/icaltypes.c
@@ -17,7 +17,7 @@
#define TMP_BUF_SIZE 1024
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
#include <pthread.h>
static pthread_mutex_t unk_token_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
@@ -174,13 +174,13 @@ ical_unknown_token_handling ical_get_unknown_token_handling_setting(void)
{
ical_unknown_token_handling myHandling;
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_lock(&unk_token_mutex);
#endif
myHandling = unknownTokenHandling;
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_unlock(&unk_token_mutex);
#endif
@@ -189,13 +189,13 @@ ical_unknown_token_handling ical_get_unknown_token_handling_setting(void)
void ical_set_unknown_token_handling_setting(ical_unknown_token_handling newSetting)
{
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_lock(&unk_token_mutex);
#endif
unknownTokenHandling = newSetting;
-#if defined(HAVE_PTHREAD)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
pthread_mutex_unlock(&unk_token_mutex);
#endif
}
diff --git a/src/libical/pvl.c b/src/libical/pvl.c
index 8faaa264..0d3e006b 100644
--- a/src/libical/pvl.c
+++ b/src/libical/pvl.c
@@ -21,7 +21,7 @@
#include <stdlib.h>
/* To mute a ThreadSanitizer claim */
-#if defined(HAVE_PTHREAD) && defined(THREAD_SANITIZER)
+#if (ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD) && defined(THREAD_SANITIZER)
#include <pthread.h>
static pthread_mutex_t pvl_mutex = PTHREAD_MUTEX_INITIALIZER;
diff --git a/src/test/builtin_timezones.c b/src/test/builtin_timezones.c
index 9271bd33..24b56f6d 100644
--- a/src/test/builtin_timezones.c
+++ b/src/test/builtin_timezones.c
@@ -12,7 +12,7 @@
#include <config.h>
#endif
-#ifdef HAVE_PTHREAD_H
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
#include <pthread.h>
#include <assert.h>
#endif
@@ -21,7 +21,7 @@
#include <stdio.h>
-#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_CREATE)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
#define N_THREADS 20
@@ -82,7 +82,7 @@ int main(void)
set_zone_directory("../../zoneinfo");
icaltimezone_set_tzid_prefix("/softwarestudio.org/");
-#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_CREATE)
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_PTHREAD
test_get_component_threadsafety();
#endif
diff --git a/src/test/icaltm_test.c b/src/test/icaltm_test.c
index 74bea858..e98e7f6a 100644
--- a/src/test/icaltm_test.c
+++ b/src/test/icaltm_test.c
@@ -16,7 +16,9 @@
#include <pthread.h>
+#if ICAL_SYNC_MODE != ICAL_SYNC_MODE_THREADLOCAL
static icaltimezone *zone, *utc;
+#endif
static void *test_tread(void *user_data)
{
@@ -24,6 +26,14 @@ static void *test_tread(void *user_data)
int ii;
_unused(user_data);
+
+#if ICAL_SYNC_MODE == ICAL_SYNC_MODE_THREADLOCAL
+ // In thread-local mode all initialization must be done per thread, so we do it here, rather
+ // than in main().
+ icaltimezone* zone = icaltimezone_get_builtin_timezone("America/New_York");
+ icaltimezone* utc = icaltimezone_get_utc_timezone();
+#endif
+
itt = icaltime_from_string("19710203T040506");
itt.zone = zone;
@@ -39,8 +49,12 @@ int main(void)
pthread_t thread[2];
int ii;
+#if ICAL_SYNC_MODE != ICAL_SYNC_MODE_THREADLOCAL
+ // In thread-local mode all initialization must be done per thread.
+ // In all other modes we do the initialization of built in timezones here.
zone = icaltimezone_get_builtin_timezone("America/New_York");
utc = icaltimezone_get_utc_timezone();
+#endif
for (ii = 0; ii < 2; ii++) {
pthread_create(&thread[ii], NULL, test_tread, NULL);