From a7ec530a6489e966461388aeec32fbc9dd5d4bef Mon Sep 17 00:00:00 2001 From: Luigi Rizzo Date: Thu, 30 Mar 2006 23:26:22 +0000 Subject: [PATCH] initial implementation of support for native atomic ops. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@16601 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- include/asterisk/lock.h | 46 +++++++++++++++++++++++++++++++++++++++++ utils.c | 11 ++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index 7c144a657f..8795bf0c3f 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -679,4 +679,50 @@ static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const str #define pthread_create __use_ast_pthread_create_instead__ #endif +/* + * Initial support for atomic instructions. + * For platforms that have it, use the native cpu instruction to + * implement them. For other platforms, resort to a 'slow' version + * (defined in utils.c) that protects the atomic instruction with + * a single lock. + * The slow versions is always available, for testing purposes, + * as ast_atomic_fetchadd_int_slow() + */ + +int ast_atomic_fetchadd_int_slow(volatile int *p, int v); + +#include "asterisk/inline_api.h" + +/*! \brief Atomically add v to *pp and return * the previous value of *p. + * This can be used to handle reference counts, and the return value + * can be used to generate unique identifiers. + */ + +#if defined ( __i386__) +AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v), +{ + __asm __volatile ( + " lock xaddl %0, %1 ; " + : "+r" (v), /* 0 (result) */ + "=m" (*p) /* 1 */ + : "m" (*p)); /* 2 */ + return (v); +}) +#else /* low performance version in utils.c */ +AST_INLINE_AP(int ast_atomic_fetchadd_int(volatile int *p, int v), +{ + return ast_atomic_fetchadd_int_slow(p, v); +}) +#endif + +/*! \brief decrement *p by 1 and return true if the variable has reached 0. + * Useful e.g. to check if a refcount has reached 0. + */ +AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p), +{ + int a = ast_atomic_fetchadd_int(p, -1); + return a == 1; /* true if the value is 0 now (so it was 1 previously) */ +} +) + #endif /* _ASTERISK_LOCK_H */ diff --git a/utils.c b/utils.c index 32c1677806..84ee0b8802 100644 --- a/utils.c +++ b/utils.c @@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#define AST_API_MODULE /* ensure that inlinable API functions will be built in lock.h if required */ #include "asterisk/lock.h" #include "asterisk/io.h" #include "asterisk/logger.h" @@ -1049,6 +1050,16 @@ void __ast_string_field_index_build(struct ast_string_field_mgr *mgr, va_end(ap2); } +AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */ +int ast_atomic_fetchadd_int_slow(volatile int *p, int v) +{ + int ret; + ast_mutex_lock(&fetchadd_m); + ret = *p; + *p += v; + ast_mutex_unlock(&fetchadd_m); + return ret; +} /*! \brief * get values from config variables.