[FFmpeg-devel] [PATCH] Add the relaxed and acquire/releae flavors of avpriv_atomic_int_get and avpriv_atomic_int_set.

Wan-Teh Chang wtc at google.com
Tue Mar 1 03:35:15 CET 2016


Correct the order of the load/store operation and the memory barrier in
avpriv_atomic_int_get and avpriv_atomic_int_set.

Use the atomic get and set functions in ff_thread_report_progress and
ff_thread_await_progress.
---
 libavcodec/pthread_frame.c | 11 +++++++----
 libavutil/atomic.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 libavutil/atomic.h         | 33 +++++++++++++++++++++++++++++++
 libavutil/atomic_gcc.h     | 44 ++++++++++++++++++++++++++++++++++++++++++
 libavutil/atomic_suncc.h   | 30 ++++++++++++++++++++++++++++-
 libavutil/atomic_win32.h   | 28 +++++++++++++++++++++++++++
 6 files changed, 189 insertions(+), 5 deletions(-)

diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index b77dd1e..34f9207 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -32,6 +32,7 @@
 #include "thread.h"
 #include "version.h"
 
+#include "libavutil/atomic.h"
 #include "libavutil/avassert.h"
 #include "libavutil/buffer.h"
 #include "libavutil/common.h"
@@ -474,7 +475,7 @@ void ff_thread_report_progress(ThreadFrame *f, int n, int field)
     PerThreadContext *p;
     volatile int *progress = f->progress ? (int*)f->progress->data : NULL;
 
-    if (!progress || progress[field] >= n) return;
+    if (!progress || avpriv_atomic_int_get_relaxed(&progress[field]) >= n) return;
 
     p = f->owner->internal->thread_ctx;
 
@@ -482,8 +483,10 @@ void ff_thread_report_progress(ThreadFrame *f, int n, int field)
         av_log(f->owner, AV_LOG_DEBUG, "%p finished %d field %d\n", progress, n, field);
 
     pthread_mutex_lock(&p->progress_mutex);
-    progress[field] = n;
-    pthread_cond_broadcast(&p->progress_cond);
+    if (progress[field] < n) {
+        avpriv_atomic_int_set_release(&progress[field], n);
+        pthread_cond_broadcast(&p->progress_cond);
+    }
     pthread_mutex_unlock(&p->progress_mutex);
 }
 
@@ -492,7 +495,7 @@ void ff_thread_await_progress(ThreadFrame *f, int n, int field)
     PerThreadContext *p;
     volatile int *progress = f->progress ? (int*)f->progress->data : NULL;
 
-    if (!progress || progress[field] >= n) return;
+    if (!progress || avpriv_atomic_int_get_acquire(&progress[field]) >= n) return;
 
     p = f->owner->internal->thread_ctx;
 
diff --git a/libavutil/atomic.c b/libavutil/atomic.c
index b13725d..3dc9062 100644
--- a/libavutil/atomic.c
+++ b/libavutil/atomic.c
@@ -40,6 +40,16 @@ int avpriv_atomic_int_get(volatile int *ptr)
     return res;
 }
 
+int avpriv_atomic_int_get_relaxed(volatile int *ptr)
+{
+    return avpriv_atomic_int_get(ptr);
+}
+
+int avpriv_atomic_int_get_acquire(volatile int *ptr)
+{
+    return avpriv_atomic_int_get(ptr);
+}
+
 void avpriv_atomic_int_set(volatile int *ptr, int val)
 {
     pthread_mutex_lock(&atomic_lock);
@@ -47,6 +57,16 @@ void avpriv_atomic_int_set(volatile int *ptr, int val)
     pthread_mutex_unlock(&atomic_lock);
 }
 
+void avpriv_atomic_int_set_relaxed(volatile int *ptr, int val)
+{
+    avpriv_atomic_int_set(ptr, val);
+}
+
+void avpriv_atomic_int_set_release(volatile int *ptr, int val)
+{
+    avpriv_atomic_int_set(ptr, val);
+}
+
 int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc)
 {
     int res;
@@ -77,11 +97,31 @@ int avpriv_atomic_int_get(volatile int *ptr)
     return *ptr;
 }
 
+int avpriv_atomic_int_get_relaxed(volatile int *ptr)
+{
+    return avpriv_atomic_int_get(ptr);
+}
+
+int avpriv_atomic_int_get_acquire(volatile int *ptr)
+{
+    return avpriv_atomic_int_get(ptr);
+}
+
 void avpriv_atomic_int_set(volatile int *ptr, int val)
 {
     *ptr = val;
 }
 
+void avpriv_atomic_int_set_relaxed(volatile int *ptr, int val)
+{
+    avpriv_atomic_int_set(ptr, val);
+}
+
+void avpriv_atomic_int_set_release(volatile int *ptr, int val)
+{
+    avpriv_atomic_int_set(ptr, val);
+}
+
 int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc)
 {
     *ptr += inc;
@@ -121,6 +161,14 @@ int main(void)
     avpriv_atomic_int_set(&val, 3);
     res = avpriv_atomic_int_get(&val);
     av_assert0(res == 3);
+    avpriv_atomic_int_set_relaxed(&val, 5);
+    res = avpriv_atomic_int_get_relaxed(&val);
+    av_assert0(res == 5);
+    res = avpriv_atomic_int_add_and_fetch(&val, -1);
+    av_assert0(res == 4);
+    avpriv_atomic_int_set_release(&val, 3);
+    res = avpriv_atomic_int_get_acquire(&val);
+    av_assert0(res == 3);
 
     return 0;
 }
diff --git a/libavutil/atomic.h b/libavutil/atomic.h
index 15906d2..1921095 100644
--- a/libavutil/atomic.h
+++ b/libavutil/atomic.h
@@ -45,6 +45,23 @@
 int avpriv_atomic_int_get(volatile int *ptr);
 
 /**
+ * Load the current value stored in an atomic integer, with no memory barrier.
+ *
+ * @param ptr atomic integer
+ * @return the current value of the atomic integer
+ */
+int avpriv_atomic_int_get_relaxed(volatile int *ptr);
+
+/**
+ * Load the current value stored in an atomic integer, with an acquire memory
+ * barrier.
+ *
+ * @param ptr atomic integer
+ * @return the current value of the atomic integer
+ */
+int avpriv_atomic_int_get_acquire(volatile int *ptr);
+
+/**
  * Store a new value in an atomic integer.
  *
  * @param ptr atomic integer
@@ -54,6 +71,22 @@ int avpriv_atomic_int_get(volatile int *ptr);
 void avpriv_atomic_int_set(volatile int *ptr, int val);
 
 /**
+ * Store a new value in an atomic integer, with no memory barrier.
+ *
+ * @param ptr atomic integer
+ * @param val the value to store in the atomic integer
+ */
+void avpriv_atomic_int_set_relaxed(volatile int *ptr, int val);
+
+/**
+ * Store a new value in an atomic integer, with a release memory barrier.
+ *
+ * @param ptr atomic integer
+ * @param val the value to store in the atomic integer
+ */
+void avpriv_atomic_int_set_release(volatile int *ptr, int val);
+
+/**
  * Add a value to an atomic integer.
  *
  * @param ptr atomic integer
diff --git a/libavutil/atomic_gcc.h b/libavutil/atomic_gcc.h
index 5f9fc49..34a6a8e 100644
--- a/libavutil/atomic_gcc.h
+++ b/libavutil/atomic_gcc.h
@@ -31,19 +31,63 @@ static inline int atomic_int_get_gcc(volatile int *ptr)
 #if HAVE_ATOMIC_COMPARE_EXCHANGE
     return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
 #else
+    int val = *ptr;
     __sync_synchronize();
+    return val;
+#endif
+}
+
+#define avpriv_atomic_int_get_relaxed atomic_int_get_gcc_relaxed
+static inline int atomic_int_get_gcc_relaxed(volatile int *ptr)
+{
+#if HAVE_ATOMIC_COMPARE_EXCHANGE
+    return __atomic_load_n(ptr, __ATOMIC_RELAXED);
+#else
     return *ptr;
 #endif
 }
 
+#define avpriv_atomic_int_get_acquire atomic_int_get_gcc_acquire
+static inline int atomic_int_get_gcc_acquire(volatile int *ptr)
+{
+#if HAVE_ATOMIC_COMPARE_EXCHANGE
+    return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
+#else
+    int val = *ptr;
+    __sync_synchronize();
+    return val;
+#endif
+}
+
 #define avpriv_atomic_int_set atomic_int_set_gcc
 static inline void atomic_int_set_gcc(volatile int *ptr, int val)
 {
 #if HAVE_ATOMIC_COMPARE_EXCHANGE
     __atomic_store_n(ptr, val, __ATOMIC_SEQ_CST);
 #else
+    __sync_synchronize();
+    *ptr = val;
+#endif
+}
+
+#define avpriv_atomic_int_set_relaxed atomic_int_set_gcc_relaxed
+static inline void atomic_int_set_gcc_relaxed(volatile int *ptr, int val)
+{
+#if HAVE_ATOMIC_COMPARE_EXCHANGE
+    __atomic_store_n(ptr, val, __ATOMIC_RELAXED);
+#else
     *ptr = val;
+#endif
+}
+
+#define avpriv_atomic_int_set_release atomic_int_set_gcc_release
+static inline void atomic_int_set_gcc_release(volatile int *ptr, int val)
+{
+#if HAVE_ATOMIC_COMPARE_EXCHANGE
+    __atomic_store_n(ptr, val, __ATOMIC_RELEASE);
+#else
     __sync_synchronize();
+    *ptr = val;
 #endif
 }
 
diff --git a/libavutil/atomic_suncc.h b/libavutil/atomic_suncc.h
index a75a37b..9b58db5 100644
--- a/libavutil/atomic_suncc.h
+++ b/libavutil/atomic_suncc.h
@@ -27,15 +27,43 @@
 #define avpriv_atomic_int_get atomic_int_get_suncc
 static inline int atomic_int_get_suncc(volatile int *ptr)
 {
+    int val = *ptr;
     __machine_rw_barrier();
+    return val;
+}
+
+#define avpriv_atomic_int_get_relaxed atomic_int_get_suncc_relaxed
+static inline int atomic_int_get_suncc_relaxed(volatile int *ptr)
+{
     return *ptr;
 }
 
+#define avpriv_atomic_int_get_acquire atomic_int_get_suncc_acquire
+static inline int atomic_int_get_suncc_acquire(volatile int *ptr)
+{
+    int val = *ptr;
+    __machine_acq_barrier()
+    return val;
+}
+
 #define avpriv_atomic_int_set atomic_int_set_suncc
 static inline void atomic_int_set_suncc(volatile int *ptr, int val)
 {
-    *ptr = val;
     __machine_rw_barrier();
+    *ptr = val;
+}
+
+#define avpriv_atomic_int_set_relaxed atomic_int_set_suncc_relaxed
+static inline void atomic_int_set_suncc_relaxed(volatile int *ptr, int val)
+{
+    *ptr = val;
+}
+
+#define avpriv_atomic_int_set_release atomic_int_set_suncc_release
+static inline void atomic_int_set_suncc_release(volatile int *ptr, int val)
+{
+    __machine_rel_barrier()
+    *ptr = val;
 }
 
 #define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_suncc
diff --git a/libavutil/atomic_win32.h b/libavutil/atomic_win32.h
index f729933..5af8847 100644
--- a/libavutil/atomic_win32.h
+++ b/libavutil/atomic_win32.h
@@ -27,15 +27,43 @@
 #define avpriv_atomic_int_get atomic_int_get_win32
 static inline int atomic_int_get_win32(volatile int *ptr)
 {
+    int val = *ptr;
     MemoryBarrier();
+    return val;
+}
+
+#define avpriv_atomic_int_get_relaxed atomic_int_get_win32_relaxed
+static inline int atomic_int_get_win32_relaxed(volatile int *ptr)
+{
     return *ptr;
 }
 
+#define avpriv_atomic_int_get_acquire atomic_int_get_win32_acquire
+static inline int atomic_int_get_win32_acquire(volatile int *ptr)
+{
+    int val = *ptr;
+    MemoryBarrier();
+    return val;
+}
+
 #define avpriv_atomic_int_set atomic_int_set_win32
 static inline void atomic_int_set_win32(volatile int *ptr, int val)
 {
+    MemoryBarrier();
+    *ptr = val;
+}
+
+#define avpriv_atomic_int_set_relaxed atomic_int_set_win32_relaxed
+static inline void atomic_int_set_win32_relaxed(volatile int *ptr, int val)
+{
     *ptr = val;
+}
+
+#define avpriv_atomic_int_set_release atomic_int_set_win32_release
+static inline void atomic_int_set_win32_release(volatile int *ptr, int val)
+{
     MemoryBarrier();
+    *ptr = val;
 }
 
 #define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_win32
-- 
2.7.0.rc3.207.g0ac5344



More information about the ffmpeg-devel mailing list