diff --git a/configure.ac b/configure.ac index bbaacf5..4f507ff 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,30 @@ AC_CHECK_DECLS([isnan], [], [], [[#include ]]) AC_CHECK_DECLS([isinf], [], [], [[#include ]]) AC_CHECK_DECLS([_isnan], [], [], [[#include ]]) AC_CHECK_DECLS([_finite], [], [], [[#include ]]) +AC_MSG_CHECKING(for GCC atomic builtins) +AC_LINK_IFELSE( +[ + AC_LANG_SOURCE([[ + int main() { + volatile unsigned int val = 1; + /* Note: __sync_val_compare_and_swap isn't checked here + * because it's protected by __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, + * which is automatically defined by gcc. + */ + __sync_add_and_fetch(&val, 1); + __sync_sub_and_fetch(&val, 1); + return 0; + } + ]]) +], +[ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_ATOMIC_BUILTINS],[1],[Has atomic builtins]) +], +[ + AC_MSG_RESULT([no]) + AC_MSG_WARN([json-c will be built without atomic refcounts because atomic builtins are missing]) +]) case "${host_os}" in linux*) diff --git a/json_object.c b/json_object.c index 028d495..c09d61d 100644 --- a/json_object.c +++ b/json_object.c @@ -165,7 +165,7 @@ extern struct json_object* json_object_get(struct json_object *jso) { if (!jso) return jso; -#if defined __GNUC__ +#ifdef HAVE_ATOMIC_BUILTINS __sync_add_and_fetch(&jso->_ref_count, 1); #else ++jso->_ref_count; @@ -178,7 +178,13 @@ int json_object_put(struct json_object *jso) { if(!jso) return 0; -#if defined __GNUC__ +#ifdef HAVE_ATOMIC_BUILTINS + /* Note: this only allow the refcount to remain correct + * when multiple threads are adjusting it. It is still an error + * for a thread to decrement the refcount if it doesn't "own" it, + * as that can result in the thread that loses the race to 0 + * operating on an already-freed object. + */ if (__sync_sub_and_fetch(&jso->_ref_count, 1) > 0) return 0; #else if (--jso->_ref_count > 0) return 0;