[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