From: "Ronald S. Bultje" <[email protected]> These could be used for reference counting, or for keeping track of decoding progress in references in multithreaded decoders.
Support is provided by gcc/msvc/suncc intrinsics, with a fallback using pthread mutexes. Signed-off-by: Anton Khirnov <[email protected]> --- configure | 7 +++ libavutil/Makefile | 2 + libavutil/atomic.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++ libavutil/atomic.h | 75 +++++++++++++++++++++++++++++ libavutil/atomic_gcc.h | 48 +++++++++++++++++++ libavutil/atomic_suncc.h | 51 ++++++++++++++++++++ libavutil/atomic_win32.h | 50 +++++++++++++++++++ 7 files changed, 353 insertions(+) create mode 100644 libavutil/atomic.c create mode 100644 libavutil/atomic.h create mode 100644 libavutil/atomic_gcc.h create mode 100644 libavutil/atomic_suncc.h create mode 100644 libavutil/atomic_win32.h diff --git a/configure b/configure index 1aae93b..2bd5aae 100755 --- a/configure +++ b/configure @@ -1271,9 +1271,11 @@ HAVE_LIST=" loongson machine_ioctl_bt848_h machine_ioctl_meteor_h + machine_rw_barrier malloc_h MapViewOfFile memalign + MemoryBarrier mkstemp mm_empty mmap @@ -1308,6 +1310,7 @@ HAVE_LIST=" struct_v4l2_frmivalenum_discrete symver_asm_label symver_gnu_asm + sync_synchronize sysconf sysctl sys_mman_h @@ -3440,6 +3443,10 @@ check_func strerror_r check_func strptime check_func strtok_r check_func sched_getaffinity +# cannot use check_func, because those are builtins +check_code ld "" "__sync_synchronize()" && enable sync_synchronize +check_code ld mbarrier.h "__machine_rw_barrier()" && enable machine_rw_barrier +check_code ld windows.h "MemoryBarrier()" && enable MemoryBarrier check_func sysconf check_func sysctl check_func usleep diff --git a/libavutil/Makefile b/libavutil/Makefile index 465b2fc..4406b13 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -54,6 +54,7 @@ BUILT_HEADERS = avconfig.h OBJS = adler32.o \ aes.o \ + atomic.o \ audio_fifo.o \ avstring.o \ base64.o \ @@ -100,6 +101,7 @@ SKIPHEADERS = old_pix_fmts.h TESTPROGS = adler32 \ aes \ + atomic \ avstring \ base64 \ blowfish \ diff --git a/libavutil/atomic.c b/libavutil/atomic.c new file mode 100644 index 0000000..9a94e61 --- /dev/null +++ b/libavutil/atomic.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2012 Ronald S. Bultje <[email protected]> + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "atomic.h" + +#if !HAVE_MEMORYBARRIER && !HAVE_SYNC_SYNCHRONIZE && !HAVE_MACHINE_RW_BARRIER + +#if HAVE_PTHREADS + +#include <pthread.h> + +static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER; + +int avpriv_atomic_int_get(volatile int *ptr) +{ + int res; + + pthread_mutex_lock(&atomic_lock); + res = *ptr; + pthread_mutex_unlock(&atomic_lock); + + return res; +} + +void avpriv_atomic_int_set(volatile int *ptr, int val) +{ + pthread_mutex_lock(&atomic_lock); + *ptr = val; + pthread_mutex_unlock(&atomic_lock); +} + +int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc) +{ + int res; + + pthread_mutex_lock(&atomic_lock); + *ptr += inc; + res = *ptr; + pthread_mutex_unlock(&atomic_lock); + + return res; +} + +void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval) +{ + void *ret; + pthread_mutex_lock(&atomic_lock); + ret = *ptr; + if (*ptr == oldval) + *ptr = newval; + pthread_mutex_unlock(&atomic_lock); + return ret; +} + +#else +// assume there is no threading at all, noop implementations of everything + +int avpriv_atomic_int_get(volatile int *ptr) +{ + return *ptr; +} + +void avpriv_atomic_int_set(volatile int *ptr, int val) +{ + *ptr = val; +} + +int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc) +{ + *ptr += inc; + return *ptr; +} + +void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval) +{ + if (*ptr == oldval) { + *ptr = newval; + return oldval; + } + return *ptr; +} + +#endif // HAVE_PTHREADS + +#endif + +#ifdef TEST +#include <assert.h> + +int main(int argc, char *argv[]) +{ + volatile int val = 1; + int res; + + res = avpriv_atomic_int_add_and_fetch(&val, 1); + assert(res == 2); + avpriv_atomic_int_set(&val, 3); + res = avpriv_atomic_int_get(&val); + assert(res == 3); + + return 0; +} +#endif diff --git a/libavutil/atomic.h b/libavutil/atomic.h new file mode 100644 index 0000000..67397d9 --- /dev/null +++ b/libavutil/atomic.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012 Ronald S. Bultje <[email protected]> + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ATOMIC_H +#define AVUTIL_ATOMIC_H + +#include "config.h" + +#if HAVE_MEMORYBARRIER +#include "atomic_win32.h" +#elif HAVE_SYNC_SYNCHRONIZE +#include "atomic_gcc.h" +#elif HAVE_MACHINE_RW_BARRIER +#include "atomic_suncc.h" +#else + +/** + * Loads the current value stored in an atomic integer. + * + * @param ptr atomic integer + * @return the current value of the atomic integer + * @note this acts as a memory barrier + */ +int avpriv_atomic_int_get(volatile int *ptr); + +/** + * Stores a new value in an atomic integer. + * + * @param ptr atomic integer + * @param val the value to store in the atomic integer + * @note this acts as a memory barrier + */ +void avpriv_atomic_int_set(volatile int *ptr, int val); + +/** + * Adds up a value to an atomic integer. + * + * @param ptr atomic integer + * @param inc the value to add up to the atomic integer (may be + * negative) + * @return the new value of the atomic integer. + * @note this does NOT act as a memory barrier. This is primarily + * intended for reference counting. + */ +int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc); + +/** + * Atomic pointer compare and swap. + * + * @param ptr pointer to the pointer to operate on + * @param oldval do the swap if the current value of *ptr equals to oldval + * @param newval value to replace *ptr with + * @return the value of *ptr before comparison + */ +void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval); + +#endif +#endif /* AVUTIL_ATOMIC_H */ diff --git a/libavutil/atomic_gcc.h b/libavutil/atomic_gcc.h new file mode 100644 index 0000000..e2f3fe1 --- /dev/null +++ b/libavutil/atomic_gcc.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012 Ronald S. Bultje <[email protected]> + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "atomic.h" + +#define avpriv_atomic_int_get atomic_int_get_gcc +static inline int atomic_int_get_gcc(volatile int *ptr) +{ + __sync_synchronize(); + return *ptr; +} + +#define avpriv_atomic_int_set atomic_int_set_gcc +static inline void atomic_int_set_gcc(volatile int *ptr, int val) +{ + *ptr = val; + __sync_synchronize(); +} + +#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_gcc +static inline int atomic_int_add_and_fetch_gcc(volatile int *ptr, int inc) +{ + return __sync_add_and_fetch(ptr, inc); +} + +#define avpriv_atomic_ptr_cas atomic_ptr_cas_gcc +static inline void *atomic_ptr_cas_gcc(void * volatile *ptr, + void *oldval, void *newval) +{ + return __sync_val_compare_and_swap(ptr, oldval, newval); +} diff --git a/libavutil/atomic_suncc.h b/libavutil/atomic_suncc.h new file mode 100644 index 0000000..85373f5 --- /dev/null +++ b/libavutil/atomic_suncc.h @@ -0,0 +1,51 @@ +/* + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <atomic.h> +#include <mbarrier.h> + +#include "atomic.h" + +#define avpriv_atomic_int_get atomic_int_get_suncc +static inline int atomic_int_get_suncc(volatile int *ptr) +{ + __machine_rw_barrier(); + return *ptr; +} + +#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(); +} + +#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_suncc +static inline int atomic_int_add_and_fetch_suncc(volatile int *ptr, int inc) +{ + return atomic_add_int_nv(ptr, inc); +} + +#define avpriv_atomic_ptr_cas atomic_ptr_cas_suncc +static inline void *atomic_ptr_cas_suncc(void * volatile *ptr, + void *oldval, void *newval) +{ + return atomic_cas_ptr(ptr, oldval, newval); +} + diff --git a/libavutil/atomic_win32.h b/libavutil/atomic_win32.h new file mode 100644 index 0000000..6ae61f6 --- /dev/null +++ b/libavutil/atomic_win32.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012 Ronald S. Bultje <[email protected]> + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <windows.h> + +#include "atomic.h" + +#define avpriv_atomic_int_get atomic_int_get_win32 +static inline int atomic_int_get_win32(volatile int *ptr) +{ + MemoryBarrier(); + return *ptr; +} + +#define avpriv_atomic_int_set atomic_int_set_win32 +static inline void atomic_int_set_win32(volatile int *ptr, int val) +{ + *ptr = val; + MemoryBarrier(); +} + +#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_win32 +static inline int atomic_int_add_and_fetch_win32(volatile int *ptr, int inc) +{ + return inc + InterlockedExchangeAdd(ptr, inc); +} + +#define avpriv_atomic_ptr_cas atomic_ptr_cas_win32 +static inline void *atomic_ptr_cas_win32(void * volatile *ptr, + void *oldval, void *newval) +{ + return InterlockedCompareExchangePointer(ptr, newval, oldval); +} -- 1.7.10.4 _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
