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.
Signed-off-by: Anton Khirnov <[email protected]> --- configure | 5 ++ libavutil/Makefile | 2 + libavutil/atomic.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++ libavutil/atomic.h | 73 ++++++++++++++++++++++++++++ libavutil/atomic_gcc.h | 48 +++++++++++++++++++ libavutil/atomic_win32.h | 50 +++++++++++++++++++ 6 files changed, 298 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_win32.h diff --git a/configure b/configure index 77600ef..7b61a88 100755 --- a/configure +++ b/configure @@ -1253,6 +1253,7 @@ HAVE_LIST=" malloc_h MapViewOfFile memalign + MemoryBarrier mkstemp mm_empty mmap @@ -1287,6 +1288,7 @@ HAVE_LIST=" struct_v4l2_frmivalenum_discrete symver_asm_label symver_gnu_asm + sync_synchronize sysconf sysctl sys_mman_h @@ -3374,6 +3376,7 @@ check_func inet_aton $network_extralibs check_func isatty check_func localtime_r check_func ${malloc_prefix}memalign && enable memalign +check_func MemoryBarrier check_func mkstemp check_func mmap check_func mprotect @@ -3384,6 +3387,8 @@ check_func strerror_r check_func strptime check_func strtok_r check_func sched_getaffinity +# cannot use check_func, because this is a builtin +check_code cc "" "__sync_synchronize()" && enable sync_synchronize 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..05dcf50 --- /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 + +#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..48717eb --- /dev/null +++ b/libavutil/atomic.h @@ -0,0 +1,73 @@ +/* + * 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" +#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_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
