aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorey Farrell <git@cfware.com>2018-01-22 14:50:37 -0500
committerCorey Farrell <git@cfware.com>2018-01-29 14:17:58 -0500
commitdc3b313e91b573f393d8717c1c9e8c11a51f7ab1 (patch)
treec7fd3b20f2edc53df1a3e94a03785cf6d1823ae8
parent9e5af7c3b77f81a7d1720073dca600e51fe9962d (diff)
downloadjansson-dc3b313e91b573f393d8717c1c9e8c11a51f7ab1.zip
jansson-dc3b313e91b573f393d8717c1c9e8c11a51f7ab1.tar.gz
jansson-dc3b313e91b573f393d8717c1c9e8c11a51f7ab1.tar.bz2
Use thread-safe reference counting if supported by the compiler.
This makes use of __atomic or __sync builtin compiler functions to make json_decref and json_incref thread-safe. Issue #387
-rw-r--r--CMakeLists.txt4
-rw-r--r--configure.ac12
-rw-r--r--src/jansson.h23
-rw-r--r--src/jansson_config.h.in8
4 files changed, 40 insertions, 7 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 68cb35b..7c1082b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -303,8 +303,8 @@ else()
set (JSON_INLINE)
endif()
-check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); return 0; } " HAVE_SYNC_BUILTINS)
-check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); return 0; }" HAVE_ATOMIC_BUILTINS)
+check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1); return 0; } " HAVE_SYNC_BUILTINS)
+check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE); return 0; }" HAVE_ATOMIC_BUILTINS)
set (JANSSON_INITIAL_HASHTABLE_ORDER 3 CACHE STRING "Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.")
diff --git a/configure.ac b/configure.ac
index d1c4faf..fa0f005 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,25 +38,33 @@ AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strto
AC_MSG_CHECKING([for gcc __sync builtins])
have_sync_builtins=no
AC_TRY_LINK(
- [], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1);],
+ [], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1);],
[have_sync_builtins=yes],
)
if test "x$have_sync_builtins" = "xyes"; then
AC_DEFINE([HAVE_SYNC_BUILTINS], [1],
[Define to 1 if gcc's __sync builtins are available])
+ json_have_sync_builtins=1
+else
+ json_have_sync_builtins=0
fi
+AC_SUBST([json_have_sync_builtins])
AC_MSG_RESULT([$have_sync_builtins])
AC_MSG_CHECKING([for gcc __atomic builtins])
have_atomic_builtins=no
AC_TRY_LINK(
- [], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE);],
+ [], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE);],
[have_atomic_builtins=yes],
)
if test "x$have_atomic_builtins" = "xyes"; then
AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1],
[Define to 1 if gcc's __atomic builtins are available])
+ json_have_atomic_builtins=1
+else
+ json_have_atomic_builtins=0
fi
+AC_SUBST([json_have_atomic_builtins])
AC_MSG_RESULT([$have_atomic_builtins])
case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in
diff --git a/src/jansson.h b/src/jansson.h
index ecf0e09..042390c 100644
--- a/src/jansson.h
+++ b/src/jansson.h
@@ -33,6 +33,11 @@ extern "C" {
(JANSSON_MINOR_VERSION << 8) | \
(JANSSON_MICRO_VERSION << 0))
+/* If __atomic or __sync builtins are available the library is thread
+ * safe for all read-only functions plus reference counting. */
+#if JSON_HAVE_ATOMIC_BUILTINS || JSON_HAVE_SYNC_BUILTINS
+#define JANSSON_THREAD_SAFE
+#endif
/* types */
@@ -49,7 +54,7 @@ typedef enum {
typedef struct json_t {
json_type type;
- size_t refcount;
+ volatile size_t refcount;
} json_t;
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
@@ -94,11 +99,23 @@ json_t *json_false(void);
#define json_boolean(val) ((val) ? json_true() : json_false())
json_t *json_null(void);
+/* do not call JSON_INTERNAL_INCREF or JSON_INTERNAL_DECREF directly */
+#if JSON_HAVE_ATOMIC_BUILTINS
+#define JSON_INTERNAL_INCREF(json) __atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE)
+#define JSON_INTERNAL_DECREF(json) __atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE)
+#elif JSON_HAVE_SYNC_BUILTINS
+#define JSON_INTERNAL_INCREF(json) __sync_add_and_fetch(&json->refcount, 1)
+#define JSON_INTERNAL_DECREF(json) __sync_sub_and_fetch(&json->refcount, 1)
+#else
+#define JSON_INTERNAL_INCREF(json) (++json->refcount)
+#define JSON_INTERNAL_DECREF(json) (--json->refcount)
+#endif
+
static JSON_INLINE
json_t *json_incref(json_t *json)
{
if(json && json->refcount != (size_t)-1)
- ++json->refcount;
+ JSON_INTERNAL_INCREF(json);
return json;
}
@@ -108,7 +125,7 @@ void json_delete(json_t *json);
static JSON_INLINE
void json_decref(json_t *json)
{
- if(json && json->refcount != (size_t)-1 && --json->refcount == 0)
+ if(json && json->refcount != (size_t)-1 && JSON_INTERNAL_DECREF(json) == 0)
json_delete(json);
}
diff --git a/src/jansson_config.h.in b/src/jansson_config.h.in
index 5e94762..fe692ab 100644
--- a/src/jansson_config.h.in
+++ b/src/jansson_config.h.in
@@ -36,6 +36,14 @@
otherwise to 0. */
#define JSON_HAVE_LOCALECONV @json_have_localeconv@
+/* If __atomic builtins are available they will be used to manage
+ reference counts of json_t. */
+#define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@
+
+/* If __atomic builtins are not available we try using __sync builtins
+ to manage reference counts of json_t. */
+#define JSON_HAVE_SYNC_BUILTINS @json_have_sync_builtins@
+
/* Maximum recursion depth for parsing JSON input.
This limits the depth of e.g. array-within-array constructions. */
#define JSON_PARSER_MAX_DEPTH 2048