Commit 535e8b60 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Rewrite vlc_atomic_* using the new atomic operations

This way, the official atomic functions will be used when available,
rather than VLC's own implementation.

This commit also enables proper atomic operations on some platforms
or with some toolchains. __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 is not
defined on some platforms such as ARM Linux, nor by other compilers
than GCC such as LLVM/clang. Then atomic operations wrongly fell
back to the lame mutex-based implementation.

This will break support for some old compilers and old or irrelevant
instruction set architectures. They would need to provide replacement
for the Intel-originated __sync_* builtin functions.
parent ad358657
...@@ -189,14 +189,25 @@ bool vlc_atomic_compare_exchange(volatile void *object, void *expected, ...@@ -189,14 +189,25 @@ bool vlc_atomic_compare_exchange(volatile void *object, void *expected,
# define VLC_ATOMIC_INIT(val) { (val) } # define VLC_ATOMIC_INIT(val) { (val) }
/* All functions return the atom value _after_ the operation. */ /* All functions return the atom value _after_ the operation. */
static inline uintptr_t vlc_atomic_get(const vlc_atomic_t *atom)
{
return atomic_load(&atom->u);
}
static inline uintptr_t vlc_atomic_set(vlc_atomic_t *atom, uintptr_t v)
{
atomic_store(&atom->u, v);
return v;
}
VLC_API uintptr_t vlc_atomic_get(const vlc_atomic_t *); static inline uintptr_t vlc_atomic_add(vlc_atomic_t *atom, uintptr_t v)
VLC_API uintptr_t vlc_atomic_set(vlc_atomic_t *, uintptr_t); {
VLC_API uintptr_t vlc_atomic_add(vlc_atomic_t *, uintptr_t); return atomic_fetch_add(&atom->u, v) + v;
}
static inline uintptr_t vlc_atomic_sub (vlc_atomic_t *atom, uintptr_t v) static inline uintptr_t vlc_atomic_sub (vlc_atomic_t *atom, uintptr_t v)
{ {
return vlc_atomic_add (atom, -v); return atomic_fetch_sub (&atom->u, v) - v;
} }
static inline uintptr_t vlc_atomic_inc (vlc_atomic_t *atom) static inline uintptr_t vlc_atomic_inc (vlc_atomic_t *atom)
...@@ -209,8 +220,16 @@ static inline uintptr_t vlc_atomic_dec (vlc_atomic_t *atom) ...@@ -209,8 +220,16 @@ static inline uintptr_t vlc_atomic_dec (vlc_atomic_t *atom)
return vlc_atomic_sub (atom, 1); return vlc_atomic_sub (atom, 1);
} }
VLC_API uintptr_t vlc_atomic_swap(vlc_atomic_t *, uintptr_t); static inline uintptr_t vlc_atomic_swap(vlc_atomic_t *atom, uintptr_t v)
VLC_API uintptr_t vlc_atomic_compare_swap(vlc_atomic_t *, uintptr_t, uintptr_t); {
return atomic_exchange(&atom->u, v);
}
static inline uintptr_t vlc_atomic_compare_swap(vlc_atomic_t *atom,
uintptr_t u, uintptr_t v)
{
return atomic_compare_exchange_strong(&atom->u, &u, v);
}
/** Helper to retrieve a single precision from an atom. */ /** Helper to retrieve a single precision from an atom. */
static inline float vlc_atomic_getf(const vlc_atomic_t *atom) static inline float vlc_atomic_getf(const vlc_atomic_t *atom)
......
...@@ -239,7 +239,6 @@ endif ...@@ -239,7 +239,6 @@ endif
SOURCES_libvlc_darwin = \ SOURCES_libvlc_darwin = \
posix/darwin_dirs.c \ posix/darwin_dirs.c \
misc/atomic.c \
posix/filesystem.c \ posix/filesystem.c \
posix/plugin.c \ posix/plugin.c \
posix/thread.c \ posix/thread.c \
...@@ -249,7 +248,6 @@ SOURCES_libvlc_darwin = \ ...@@ -249,7 +248,6 @@ SOURCES_libvlc_darwin = \
SOURCES_libvlc_linux = \ SOURCES_libvlc_linux = \
posix/dirs.c \ posix/dirs.c \
misc/atomic.c \
posix/filesystem.c \ posix/filesystem.c \
posix/plugin.c \ posix/plugin.c \
posix/thread.c \ posix/thread.c \
...@@ -261,7 +259,6 @@ SOURCES_libvlc_linux = \ ...@@ -261,7 +259,6 @@ SOURCES_libvlc_linux = \
SOURCES_libvlc_win32 = \ SOURCES_libvlc_win32 = \
win32/dirs.c \ win32/dirs.c \
win32/atomic.c \
win32/filesystem.c \ win32/filesystem.c \
win32/plugin.c \ win32/plugin.c \
win32/thread.c \ win32/thread.c \
...@@ -273,7 +270,6 @@ SOURCES_libvlc_win32 = \ ...@@ -273,7 +270,6 @@ SOURCES_libvlc_win32 = \
SOURCES_libvlc_symbian = \ SOURCES_libvlc_symbian = \
symbian/path.cpp \ symbian/path.cpp \
symbian/dirs.c \ symbian/dirs.c \
misc/atomic.c \
win32/plugin.c \ win32/plugin.c \
posix/rand.c \ posix/rand.c \
$(NULL) $(NULL)
...@@ -281,7 +277,6 @@ SOURCES_libvlc_symbian = \ ...@@ -281,7 +277,6 @@ SOURCES_libvlc_symbian = \
SOURCES_libvlc_os2 = \ SOURCES_libvlc_os2 = \
os2/getaddrinfo.c \ os2/getaddrinfo.c \
os2/dirs.c \ os2/dirs.c \
misc/atomic.c \
os2/filesystem.c \ os2/filesystem.c \
os2/plugin.c \ os2/plugin.c \
os2/thread.c \ os2/thread.c \
...@@ -291,7 +286,6 @@ SOURCES_libvlc_os2 = \ ...@@ -291,7 +286,6 @@ SOURCES_libvlc_os2 = \
SOURCES_libvlc_other = \ SOURCES_libvlc_other = \
posix/dirs.c \ posix/dirs.c \
misc/atomic.c \
posix/filesystem.c \ posix/filesystem.c \
posix/thread.c \ posix/thread.c \
posix/plugin.c \ posix/plugin.c \
......
...@@ -489,11 +489,6 @@ vlc_clone ...@@ -489,11 +489,6 @@ vlc_clone
VLC_CompileBy VLC_CompileBy
VLC_CompileHost VLC_CompileHost
VLC_Compiler VLC_Compiler
vlc_atomic_get
vlc_atomic_set
vlc_atomic_add
vlc_atomic_swap
vlc_atomic_compare_swap
vlc_cond_broadcast vlc_cond_broadcast
vlc_cond_destroy vlc_cond_destroy
vlc_cond_init vlc_cond_init
......
/*****************************************************************************
* atomic.c:
*****************************************************************************
* Copyright (C) 2010 Rémi Denis-Courmont
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <vlc_common.h>
#include <vlc_atomic.h>
#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
/* GCC intrinsics */
uintptr_t vlc_atomic_get (const vlc_atomic_t *atom)
{
__sync_synchronize ();
return atom->u;
}
uintptr_t vlc_atomic_set (vlc_atomic_t *atom, uintptr_t v)
{
atom->u = v;
__sync_synchronize ();
return v;
}
uintptr_t vlc_atomic_add (vlc_atomic_t *atom, uintptr_t v)
{
return __sync_add_and_fetch (&atom->u, v);
}
uintptr_t vlc_atomic_swap (vlc_atomic_t *atom, uintptr_t v)
{
/* grmbl, gcc does not provide an intrinsic for this! */
uintptr_t u;
do
u = vlc_atomic_get (atom);
while (vlc_atomic_compare_swap (atom, u, v) != u);
return u;
}
uintptr_t vlc_atomic_compare_swap (vlc_atomic_t *atom,
uintptr_t oldval, uintptr_t newval)
{
return __sync_val_compare_and_swap (&atom->u, oldval, newval);
}
#else
/* Worst-case fallback implementation with a mutex */
static vlc_mutex_t lock = VLC_STATIC_MUTEX;
uintptr_t vlc_atomic_get (const vlc_atomic_t *atom)
{
uintptr_t v;
vlc_mutex_lock (&lock);
v = atom->u;
vlc_mutex_unlock (&lock);
return v;
}
uintptr_t vlc_atomic_set (vlc_atomic_t *atom, uintptr_t v)
{
vlc_mutex_lock (&lock);
atom->u = v;
vlc_mutex_unlock (&lock);
return v;
}
uintptr_t vlc_atomic_add (vlc_atomic_t *atom, uintptr_t v)
{
vlc_mutex_lock (&lock);
atom->u += v;
v = atom->u;
vlc_mutex_unlock (&lock);
return v;
}
uintptr_t vlc_atomic_swap (vlc_atomic_t *atom, uintptr_t v)
{
uintptr_t u;
vlc_mutex_lock (&lock);
u = atom->u;
atom->u = v;
vlc_mutex_unlock (&lock);
return u;
}
uintptr_t vlc_atomic_compare_swap (vlc_atomic_t *atom,
uintptr_t oldval, uintptr_t newval)
{
uintptr_t u;
vlc_mutex_lock (&lock);
u = atom->u;
if (u == oldval)
atom->u = newval;
vlc_mutex_unlock (&lock);
return u;
}
#endif
/*****************************************************************************
* atomic.c:
*****************************************************************************
* Copyright (C) 2010 Rémi Denis-Courmont
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <vlc_common.h>
#include <vlc_atomic.h>
#include <windows.h>
uintptr_t vlc_atomic_get (const vlc_atomic_t *atom)
{
return atom->u;
}
uintptr_t vlc_atomic_set (vlc_atomic_t *atom, uintptr_t v)
{
#if defined (WIN64)
InterlockedExchange64 (&atom->u, v);
#else
InterlockedExchange (&atom->u, v);
#endif
return v;
}
uintptr_t vlc_atomic_add (vlc_atomic_t *atom, uintptr_t v)
{
#if defined (WIN64)
return InterlockedExchangeAdd64 (&atom->s, v) + v;
#else
return InterlockedExchangeAdd (&atom->s, v) + v;
#endif
}
uintptr_t vlc_atomic_swap (vlc_atomic_t *atom, uintptr_t v)
{
#if defined (WIN64)
return InterlockedExchange64 (&atom->s, v);
#else
return InterlockedExchange (&atom->s, v);
#endif
}
uintptr_t vlc_atomic_compare_swap (vlc_atomic_t *atom,
uintptr_t oldval, uintptr_t newval)
{
#if defined (WIN64)
return InterlockedCompareExchange64 (&atom->s, newval, oldval);
#else
return InterlockedCompareExchange (&atom->s, newval, oldval);
#endif
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment