initial implementation of support for native atomic ops.
authorLuigi Rizzo <rizzo@icir.org>
Thu, 30 Mar 2006 23:26:22 +0000 (23:26 +0000)
committerLuigi Rizzo <rizzo@icir.org>
Thu, 30 Mar 2006 23:26:22 +0000 (23:26 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@16601 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/lock.h
utils.c

index 7c144a6..8795bf0 100644 (file)
@@ -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 32c1677..84ee0b8 100644 (file)
--- 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.