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)
|
set (JSON_INLINE)
|
||||||
endif()
|
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() { 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); return 0; }" HAVE_ATOMIC_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.")
|
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])
|
AC_MSG_CHECKING([for gcc __sync builtins])
|
||||||
have_sync_builtins=no
|
have_sync_builtins=no
|
||||||
AC_TRY_LINK(
|
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],
|
[have_sync_builtins=yes],
|
||||||
)
|
)
|
||||||
if test "x$have_sync_builtins" = "xyes"; then
|
if test "x$have_sync_builtins" = "xyes"; then
|
||||||
AC_DEFINE([HAVE_SYNC_BUILTINS], [1],
|
AC_DEFINE([HAVE_SYNC_BUILTINS], [1],
|
||||||
[Define to 1 if gcc's __sync builtins are available])
|
[Define to 1 if gcc's __sync builtins are available])
|
||||||
|
json_have_sync_builtins=1
|
||||||
|
else
|
||||||
|
json_have_sync_builtins=0
|
||||||
fi
|
fi
|
||||||
|
AC_SUBST([json_have_sync_builtins])
|
||||||
AC_MSG_RESULT([$have_sync_builtins])
|
AC_MSG_RESULT([$have_sync_builtins])
|
||||||
|
|
||||||
AC_MSG_CHECKING([for gcc __atomic builtins])
|
AC_MSG_CHECKING([for gcc __atomic builtins])
|
||||||
have_atomic_builtins=no
|
have_atomic_builtins=no
|
||||||
AC_TRY_LINK(
|
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],
|
[have_atomic_builtins=yes],
|
||||||
)
|
)
|
||||||
if test "x$have_atomic_builtins" = "xyes"; then
|
if test "x$have_atomic_builtins" = "xyes"; then
|
||||||
AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1],
|
AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1],
|
||||||
[Define to 1 if gcc's __atomic builtins are available])
|
[Define to 1 if gcc's __atomic builtins are available])
|
||||||
|
json_have_atomic_builtins=1
|
||||||
|
else
|
||||||
|
json_have_atomic_builtins=0
|
||||||
fi
|
fi
|
||||||
|
AC_SUBST([json_have_atomic_builtins])
|
||||||
AC_MSG_RESULT([$have_atomic_builtins])
|
AC_MSG_RESULT([$have_atomic_builtins])
|
||||||
|
|
||||||
case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in
|
case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in
|
||||||
|
@ -33,6 +33,11 @@ extern "C" {
|
|||||||
(JANSSON_MINOR_VERSION << 8) | \
|
(JANSSON_MINOR_VERSION << 8) | \
|
||||||
(JANSSON_MICRO_VERSION << 0))
|
(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 */
|
/* types */
|
||||||
|
|
||||||
@ -49,7 +54,7 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct json_t {
|
typedef struct json_t {
|
||||||
json_type type;
|
json_type type;
|
||||||
size_t refcount;
|
volatile size_t refcount;
|
||||||
} json_t;
|
} json_t;
|
||||||
|
|
||||||
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
|
#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())
|
#define json_boolean(val) ((val) ? json_true() : json_false())
|
||||||
json_t *json_null(void);
|
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
|
static JSON_INLINE
|
||||||
json_t *json_incref(json_t *json)
|
json_t *json_incref(json_t *json)
|
||||||
{
|
{
|
||||||
if(json && json->refcount != (size_t)-1)
|
if(json && json->refcount != (size_t)-1)
|
||||||
++json->refcount;
|
JSON_INTERNAL_INCREF(json);
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +125,7 @@ void json_delete(json_t *json);
|
|||||||
static JSON_INLINE
|
static JSON_INLINE
|
||||||
void json_decref(json_t *json)
|
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);
|
json_delete(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,14 @@
|
|||||||
otherwise to 0. */
|
otherwise to 0. */
|
||||||
#define JSON_HAVE_LOCALECONV @json_have_localeconv@
|
#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.
|
/* Maximum recursion depth for parsing JSON input.
|
||||||
This limits the depth of e.g. array-within-array constructions. */
|
This limits the depth of e.g. array-within-array constructions. */
|
||||||
#define JSON_PARSER_MAX_DEPTH 2048
|
#define JSON_PARSER_MAX_DEPTH 2048
|
||||||
|
Loading…
Reference in New Issue
Block a user