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
This commit is contained in:
parent
9e5af7c3b7
commit
dc3b313e91
@ -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.")
|
||||
|
||||
|
12
configure.ac
12
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user