Moved interlocked functions to libwine_port.
This commit is contained in:
parent
f94c8b85b9
commit
108a69bd2f
|
@ -164,15 +164,11 @@ struct statfs;
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Function definitions (only when using libwine)
|
* Function definitions (only when using libwine_port)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NO_LIBWINE_PORT
|
#ifndef NO_LIBWINE_PORT
|
||||||
|
|
||||||
#if !defined(HAVE_CLONE) && defined(linux)
|
|
||||||
int clone(int (*fn)(void *arg), void *stack, int flags, void *arg);
|
|
||||||
#endif /* !defined(HAVE_CLONE) && defined(linux) */
|
|
||||||
|
|
||||||
#ifndef HAVE_GETOPT_LONG
|
#ifndef HAVE_GETOPT_LONG
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind;
|
extern int optind;
|
||||||
|
@ -255,7 +251,7 @@ extern int mkstemps(char *template, int suffix_len);
|
||||||
|
|
||||||
#if defined(__i386__) && defined(__GNUC__)
|
#if defined(__i386__) && defined(__GNUC__)
|
||||||
|
|
||||||
inline static long interlocked_cmpxchg( long *dest, long xchg, long compare )
|
extern inline long interlocked_cmpxchg( long *dest, long xchg, long compare )
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
__asm__ __volatile__( "lock; cmpxchgl %2,(%1)"
|
__asm__ __volatile__( "lock; cmpxchgl %2,(%1)"
|
||||||
|
@ -263,7 +259,7 @@ inline static long interlocked_cmpxchg( long *dest, long xchg, long compare )
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
|
extern inline void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
__asm__ __volatile__( "lock; cmpxchgl %2,(%1)"
|
__asm__ __volatile__( "lock; cmpxchgl %2,(%1)"
|
||||||
|
@ -271,7 +267,7 @@ inline static void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *comp
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static long interlocked_xchg( long *dest, long val )
|
extern inline long interlocked_xchg( long *dest, long val )
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
__asm__ __volatile__( "lock; xchgl %0,(%1)"
|
__asm__ __volatile__( "lock; xchgl %0,(%1)"
|
||||||
|
@ -279,7 +275,7 @@ inline static long interlocked_xchg( long *dest, long val )
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void *interlocked_xchg_ptr( void **dest, void *val )
|
extern inline void *interlocked_xchg_ptr( void **dest, void *val )
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
__asm__ __volatile__( "lock; xchgl %0,(%1)"
|
__asm__ __volatile__( "lock; xchgl %0,(%1)"
|
||||||
|
@ -287,7 +283,7 @@ inline static void *interlocked_xchg_ptr( void **dest, void *val )
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static long interlocked_xchg_add( long *dest, long incr )
|
extern inline long interlocked_xchg_add( long *dest, long incr )
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
__asm__ __volatile__( "lock; xaddl %0,(%1)"
|
__asm__ __volatile__( "lock; xaddl %0,(%1)"
|
||||||
|
@ -309,17 +305,23 @@ extern long interlocked_xchg_add( long *dest, long incr );
|
||||||
|
|
||||||
#define __WINE_NOT_PORTABLE(func) func##_is_not_portable func##_is_not_portable
|
#define __WINE_NOT_PORTABLE(func) func##_is_not_portable func##_is_not_portable
|
||||||
|
|
||||||
#define clone __WINE_NOT_PORTABLE(clone)
|
#define getopt_long __WINE_NOT_PORTABLE(getopt_long)
|
||||||
#define getpagesize __WINE_NOT_PORTABLE(getpagesize)
|
#define getopt_long_only __WINE_NOT_PORTABLE(getopt_long_only)
|
||||||
#define lstat __WINE_NOT_PORTABLE(lstat)
|
#define getpagesize __WINE_NOT_PORTABLE(getpagesize)
|
||||||
#define memmove __WINE_NOT_PORTABLE(memmove)
|
#define interlocked_cmpxchg __WINE_NOT_PORTABLE(interlocked_cmpxchg)
|
||||||
#define pread __WINE_NOT_PORTABLE(pread)
|
#define interlocked_cmpxchg_ptr __WINE_NOT_PORTABLE(interlocked_cmpxchg_ptr)
|
||||||
#define pwrite __WINE_NOT_PORTABLE(pwrite)
|
#define interlocked_xchg __WINE_NOT_PORTABLE(interlocked_xchg)
|
||||||
#define statfs __WINE_NOT_PORTABLE(statfs)
|
#define interlocked_xchg_ptr __WINE_NOT_PORTABLE(interlocked_xchg_ptr)
|
||||||
#define strcasecmp __WINE_NOT_PORTABLE(strcasecmp)
|
#define interlocked_xchg_add __WINE_NOT_PORTABLE(interlocked_xchg_add)
|
||||||
#define strerror __WINE_NOT_PORTABLE(strerror)
|
#define lstat __WINE_NOT_PORTABLE(lstat)
|
||||||
#define strncasecmp __WINE_NOT_PORTABLE(strncasecmp)
|
#define memmove __WINE_NOT_PORTABLE(memmove)
|
||||||
#define usleep __WINE_NOT_PORTABLE(usleep)
|
#define pread __WINE_NOT_PORTABLE(pread)
|
||||||
|
#define pwrite __WINE_NOT_PORTABLE(pwrite)
|
||||||
|
#define statfs __WINE_NOT_PORTABLE(statfs)
|
||||||
|
#define strcasecmp __WINE_NOT_PORTABLE(strcasecmp)
|
||||||
|
#define strerror __WINE_NOT_PORTABLE(strerror)
|
||||||
|
#define strncasecmp __WINE_NOT_PORTABLE(strncasecmp)
|
||||||
|
#define usleep __WINE_NOT_PORTABLE(usleep)
|
||||||
|
|
||||||
#endif /* NO_LIBWINE_PORT */
|
#endif /* NO_LIBWINE_PORT */
|
||||||
|
|
||||||
|
|
225
library/port.c
225
library/port.c
|
@ -271,228 +271,3 @@ void pthread_mutex_unlock() { assert(0); }
|
||||||
#ifndef HAVE_PTHREAD_SETSPECIFIC
|
#ifndef HAVE_PTHREAD_SETSPECIFIC
|
||||||
void pthread_setspecific() { assert(0); }
|
void pthread_setspecific() { assert(0); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* interlocked functions
|
|
||||||
*/
|
|
||||||
#ifdef __i386__
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
|
|
||||||
__ASM_GLOBAL_FUNC(interlocked_cmpxchg,
|
|
||||||
"movl 12(%esp),%eax\n\t"
|
|
||||||
"movl 8(%esp),%ecx\n\t"
|
|
||||||
"movl 4(%esp),%edx\n\t"
|
|
||||||
"lock; cmpxchgl %ecx,(%edx)\n\t"
|
|
||||||
"ret");
|
|
||||||
__ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
|
|
||||||
"movl 12(%esp),%eax\n\t"
|
|
||||||
"movl 8(%esp),%ecx\n\t"
|
|
||||||
"movl 4(%esp),%edx\n\t"
|
|
||||||
"lock; cmpxchgl %ecx,(%edx)\n\t"
|
|
||||||
"ret");
|
|
||||||
__ASM_GLOBAL_FUNC(interlocked_xchg,
|
|
||||||
"movl 8(%esp),%eax\n\t"
|
|
||||||
"movl 4(%esp),%edx\n\t"
|
|
||||||
"lock; xchgl %eax,(%edx)\n\t"
|
|
||||||
"ret");
|
|
||||||
__ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
|
|
||||||
"movl 8(%esp),%eax\n\t"
|
|
||||||
"movl 4(%esp),%edx\n\t"
|
|
||||||
"lock; xchgl %eax,(%edx)\n\t"
|
|
||||||
"ret");
|
|
||||||
__ASM_GLOBAL_FUNC(interlocked_xchg_add,
|
|
||||||
"movl 8(%esp),%eax\n\t"
|
|
||||||
"movl 4(%esp),%edx\n\t"
|
|
||||||
"lock; xaddl %eax,(%edx)\n\t"
|
|
||||||
"ret");
|
|
||||||
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
|
|
||||||
__declspec(naked) long interlocked_cmpxchg( long *dest, long xchg, long compare )
|
|
||||||
{
|
|
||||||
__asm mov eax, 12[esp];
|
|
||||||
__asm mov ecx, 8[esp];
|
|
||||||
__asm mov edx, 4[esp];
|
|
||||||
__asm lock cmpxchg [edx], ecx;
|
|
||||||
__asm ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
|
|
||||||
{
|
|
||||||
__asm mov eax, 12[esp];
|
|
||||||
__asm mov ecx, 8[esp];
|
|
||||||
__asm mov edx, 4[esp];
|
|
||||||
__asm lock cmpxchg [edx], ecx;
|
|
||||||
__asm ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(naked) long interlocked_xchg( long *dest, long val )
|
|
||||||
{
|
|
||||||
__asm mov eax, 8[esp];
|
|
||||||
__asm mov edx, 4[esp];
|
|
||||||
__asm lock xchg [edx], eax;
|
|
||||||
__asm ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
|
|
||||||
{
|
|
||||||
__asm mov eax, 8[esp];
|
|
||||||
__asm mov edx, 4[esp];
|
|
||||||
__asm lock xchg [edx], eax;
|
|
||||||
__asm ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(naked) long interlocked_xchg_add( long *dest, long incr )
|
|
||||||
{
|
|
||||||
__asm mov eax, 8[esp];
|
|
||||||
__asm mov edx, 4[esp];
|
|
||||||
__asm lock xadd [edx], eax;
|
|
||||||
__asm ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
# error You must implement the interlocked* functions for your compiler
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif defined(__powerpc__)
|
|
||||||
void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
|
|
||||||
{
|
|
||||||
long ret = 0;
|
|
||||||
long scratch;
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"0: lwarx %0,0,%2 ;"
|
|
||||||
" xor. %1,%4,%0;"
|
|
||||||
" bne 1f;"
|
|
||||||
" stwcx. %3,0,%2;"
|
|
||||||
" bne- 0b;"
|
|
||||||
"1: "
|
|
||||||
: "=&r"(ret), "=&r"(scratch)
|
|
||||||
: "r"(dest), "r"(xchg), "r"(compare)
|
|
||||||
: "cr0","memory");
|
|
||||||
return (void*)ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
long interlocked_cmpxchg( long *dest, long xchg, long compare)
|
|
||||||
{
|
|
||||||
long ret = 0;
|
|
||||||
long scratch;
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"0: lwarx %0,0,%2 ;"
|
|
||||||
" xor. %1,%4,%0;"
|
|
||||||
" bne 1f;"
|
|
||||||
" stwcx. %3,0,%2;"
|
|
||||||
" bne- 0b;"
|
|
||||||
"1: "
|
|
||||||
: "=&r"(ret), "=&r"(scratch)
|
|
||||||
: "r"(dest), "r"(xchg), "r"(compare)
|
|
||||||
: "cr0","memory");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
long interlocked_xchg_add( long *dest, long incr )
|
|
||||||
{
|
|
||||||
long ret = 0;
|
|
||||||
long zero = 0;
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"0: lwarx %0, %3, %1;"
|
|
||||||
" add %0, %2, %0;"
|
|
||||||
" stwcx. %0, %3, %1;"
|
|
||||||
" bne- 0b;"
|
|
||||||
: "=&r" (ret)
|
|
||||||
: "r"(dest), "r"(incr), "r"(zero)
|
|
||||||
: "cr0", "memory"
|
|
||||||
);
|
|
||||||
return ret-incr;
|
|
||||||
}
|
|
||||||
|
|
||||||
long interlocked_xchg( long* dest, long val )
|
|
||||||
{
|
|
||||||
long ret = 0;
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"0: lwarx %0,0,%1 ;"
|
|
||||||
" stwcx. %2,0,%1;"
|
|
||||||
" bne- 0b;"
|
|
||||||
: "=&r"(ret)
|
|
||||||
: "r"(dest), "r"(val)
|
|
||||||
: "cr0","memory");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* interlocked_xchg_ptr( void** dest, void* val )
|
|
||||||
{
|
|
||||||
void *ret = NULL;
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"0: lwarx %0,0,%1 ;"
|
|
||||||
" stwcx. %2,0,%1;"
|
|
||||||
" bne- 0b;"
|
|
||||||
: "=&r"(ret)
|
|
||||||
: "r"(dest), "r"(val)
|
|
||||||
: "cr0","memory");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(__sparc__) && defined(__sun__)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* As the earlier Sparc processors lack necessary atomic instructions,
|
|
||||||
* I'm simply falling back to the library-provided _lwp_mutex routines
|
|
||||||
* to ensure mutual exclusion in a way appropriate for the current
|
|
||||||
* architecture.
|
|
||||||
*
|
|
||||||
* FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
|
|
||||||
* we could use this to speed up the Interlocked operations ...
|
|
||||||
*/
|
|
||||||
#include <synch.h>
|
|
||||||
static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
|
|
||||||
|
|
||||||
long interlocked_cmpxchg( long *dest, long xchg, long compare )
|
|
||||||
{
|
|
||||||
_lwp_mutex_lock( &interlocked_mutex );
|
|
||||||
if (*dest == compare) *dest = xchg;
|
|
||||||
else compare = *dest;
|
|
||||||
_lwp_mutex_unlock( &interlocked_mutex );
|
|
||||||
return compare;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
|
|
||||||
{
|
|
||||||
_lwp_mutex_lock( &interlocked_mutex );
|
|
||||||
if (*dest == compare) *dest = xchg;
|
|
||||||
else compare = *dest;
|
|
||||||
_lwp_mutex_unlock( &interlocked_mutex );
|
|
||||||
return compare;
|
|
||||||
}
|
|
||||||
|
|
||||||
long interlocked_xchg( long *dest, long val )
|
|
||||||
{
|
|
||||||
long retv;
|
|
||||||
_lwp_mutex_lock( &interlocked_mutex );
|
|
||||||
retv = *dest;
|
|
||||||
*dest = val;
|
|
||||||
_lwp_mutex_unlock( &interlocked_mutex );
|
|
||||||
return retv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *interlocked_xchg_ptr( void **dest, void *val )
|
|
||||||
{
|
|
||||||
long retv;
|
|
||||||
_lwp_mutex_lock( &interlocked_mutex );
|
|
||||||
retv = *dest;
|
|
||||||
*dest = val;
|
|
||||||
_lwp_mutex_unlock( &interlocked_mutex );
|
|
||||||
return retv;
|
|
||||||
}
|
|
||||||
|
|
||||||
long interlocked_xchg_add( long *dest, long incr )
|
|
||||||
{
|
|
||||||
long retv;
|
|
||||||
_lwp_mutex_lock( &interlocked_mutex );
|
|
||||||
retv = *dest;
|
|
||||||
*dest += incr;
|
|
||||||
_lwp_mutex_unlock( &interlocked_mutex );
|
|
||||||
return retv;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
# error You must implement the interlocked* functions for your CPU
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ C_SRCS = \
|
||||||
getopt.c \
|
getopt.c \
|
||||||
getopt1.c \
|
getopt1.c \
|
||||||
getpagesize.c \
|
getpagesize.c \
|
||||||
|
interlocked.c \
|
||||||
lstat.c \
|
lstat.c \
|
||||||
memmove.c \
|
memmove.c \
|
||||||
mkstemps.c \
|
mkstemps.c \
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
/*
|
||||||
|
* interlocked functions
|
||||||
|
*
|
||||||
|
* Copyright 1996 Alexandre Julliard
|
||||||
|
*
|
||||||
|
* This library 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 library 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 library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "wine/port.h"
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
|
||||||
|
__ASM_GLOBAL_FUNC(interlocked_cmpxchg,
|
||||||
|
"movl 12(%esp),%eax\n\t"
|
||||||
|
"movl 8(%esp),%ecx\n\t"
|
||||||
|
"movl 4(%esp),%edx\n\t"
|
||||||
|
"lock; cmpxchgl %ecx,(%edx)\n\t"
|
||||||
|
"ret");
|
||||||
|
__ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
|
||||||
|
"movl 12(%esp),%eax\n\t"
|
||||||
|
"movl 8(%esp),%ecx\n\t"
|
||||||
|
"movl 4(%esp),%edx\n\t"
|
||||||
|
"lock; cmpxchgl %ecx,(%edx)\n\t"
|
||||||
|
"ret");
|
||||||
|
__ASM_GLOBAL_FUNC(interlocked_xchg,
|
||||||
|
"movl 8(%esp),%eax\n\t"
|
||||||
|
"movl 4(%esp),%edx\n\t"
|
||||||
|
"lock; xchgl %eax,(%edx)\n\t"
|
||||||
|
"ret");
|
||||||
|
__ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
|
||||||
|
"movl 8(%esp),%eax\n\t"
|
||||||
|
"movl 4(%esp),%edx\n\t"
|
||||||
|
"lock; xchgl %eax,(%edx)\n\t"
|
||||||
|
"ret");
|
||||||
|
__ASM_GLOBAL_FUNC(interlocked_xchg_add,
|
||||||
|
"movl 8(%esp),%eax\n\t"
|
||||||
|
"movl 4(%esp),%edx\n\t"
|
||||||
|
"lock; xaddl %eax,(%edx)\n\t"
|
||||||
|
"ret");
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
|
__declspec(naked) long interlocked_cmpxchg( long *dest, long xchg, long compare )
|
||||||
|
{
|
||||||
|
__asm mov eax, 12[esp];
|
||||||
|
__asm mov ecx, 8[esp];
|
||||||
|
__asm mov edx, 4[esp];
|
||||||
|
__asm lock cmpxchg [edx], ecx;
|
||||||
|
__asm ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
|
||||||
|
{
|
||||||
|
__asm mov eax, 12[esp];
|
||||||
|
__asm mov ecx, 8[esp];
|
||||||
|
__asm mov edx, 4[esp];
|
||||||
|
__asm lock cmpxchg [edx], ecx;
|
||||||
|
__asm ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) long interlocked_xchg( long *dest, long val )
|
||||||
|
{
|
||||||
|
__asm mov eax, 8[esp];
|
||||||
|
__asm mov edx, 4[esp];
|
||||||
|
__asm lock xchg [edx], eax;
|
||||||
|
__asm ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
|
||||||
|
{
|
||||||
|
__asm mov eax, 8[esp];
|
||||||
|
__asm mov edx, 4[esp];
|
||||||
|
__asm lock xchg [edx], eax;
|
||||||
|
__asm ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) long interlocked_xchg_add( long *dest, long incr )
|
||||||
|
{
|
||||||
|
__asm mov eax, 8[esp];
|
||||||
|
__asm mov edx, 4[esp];
|
||||||
|
__asm lock xadd [edx], eax;
|
||||||
|
__asm ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error You must implement the interlocked* functions for your compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__powerpc__)
|
||||||
|
void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
|
||||||
|
{
|
||||||
|
long ret = 0;
|
||||||
|
long scratch;
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"0: lwarx %0,0,%2 ;"
|
||||||
|
" xor. %1,%4,%0;"
|
||||||
|
" bne 1f;"
|
||||||
|
" stwcx. %3,0,%2;"
|
||||||
|
" bne- 0b;"
|
||||||
|
"1: "
|
||||||
|
: "=&r"(ret), "=&r"(scratch)
|
||||||
|
: "r"(dest), "r"(xchg), "r"(compare)
|
||||||
|
: "cr0","memory");
|
||||||
|
return (void*)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
long interlocked_cmpxchg( long *dest, long xchg, long compare)
|
||||||
|
{
|
||||||
|
long ret = 0;
|
||||||
|
long scratch;
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"0: lwarx %0,0,%2 ;"
|
||||||
|
" xor. %1,%4,%0;"
|
||||||
|
" bne 1f;"
|
||||||
|
" stwcx. %3,0,%2;"
|
||||||
|
" bne- 0b;"
|
||||||
|
"1: "
|
||||||
|
: "=&r"(ret), "=&r"(scratch)
|
||||||
|
: "r"(dest), "r"(xchg), "r"(compare)
|
||||||
|
: "cr0","memory");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
long interlocked_xchg_add( long *dest, long incr )
|
||||||
|
{
|
||||||
|
long ret = 0;
|
||||||
|
long zero = 0;
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"0: lwarx %0, %3, %1;"
|
||||||
|
" add %0, %2, %0;"
|
||||||
|
" stwcx. %0, %3, %1;"
|
||||||
|
" bne- 0b;"
|
||||||
|
: "=&r" (ret)
|
||||||
|
: "r"(dest), "r"(incr), "r"(zero)
|
||||||
|
: "cr0", "memory"
|
||||||
|
);
|
||||||
|
return ret-incr;
|
||||||
|
}
|
||||||
|
|
||||||
|
long interlocked_xchg( long* dest, long val )
|
||||||
|
{
|
||||||
|
long ret = 0;
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"0: lwarx %0,0,%1 ;"
|
||||||
|
" stwcx. %2,0,%1;"
|
||||||
|
" bne- 0b;"
|
||||||
|
: "=&r"(ret)
|
||||||
|
: "r"(dest), "r"(val)
|
||||||
|
: "cr0","memory");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* interlocked_xchg_ptr( void** dest, void* val )
|
||||||
|
{
|
||||||
|
void *ret = NULL;
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"0: lwarx %0,0,%1 ;"
|
||||||
|
" stwcx. %2,0,%1;"
|
||||||
|
" bne- 0b;"
|
||||||
|
: "=&r"(ret)
|
||||||
|
: "r"(dest), "r"(val)
|
||||||
|
: "cr0","memory");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__sparc__) && defined(__sun__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As the earlier Sparc processors lack necessary atomic instructions,
|
||||||
|
* I'm simply falling back to the library-provided _lwp_mutex routines
|
||||||
|
* to ensure mutual exclusion in a way appropriate for the current
|
||||||
|
* architecture.
|
||||||
|
*
|
||||||
|
* FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
|
||||||
|
* we could use this to speed up the Interlocked operations ...
|
||||||
|
*/
|
||||||
|
#include <synch.h>
|
||||||
|
static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
|
||||||
|
|
||||||
|
long interlocked_cmpxchg( long *dest, long xchg, long compare )
|
||||||
|
{
|
||||||
|
_lwp_mutex_lock( &interlocked_mutex );
|
||||||
|
if (*dest == compare) *dest = xchg;
|
||||||
|
else compare = *dest;
|
||||||
|
_lwp_mutex_unlock( &interlocked_mutex );
|
||||||
|
return compare;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
|
||||||
|
{
|
||||||
|
_lwp_mutex_lock( &interlocked_mutex );
|
||||||
|
if (*dest == compare) *dest = xchg;
|
||||||
|
else compare = *dest;
|
||||||
|
_lwp_mutex_unlock( &interlocked_mutex );
|
||||||
|
return compare;
|
||||||
|
}
|
||||||
|
|
||||||
|
long interlocked_xchg( long *dest, long val )
|
||||||
|
{
|
||||||
|
long retv;
|
||||||
|
_lwp_mutex_lock( &interlocked_mutex );
|
||||||
|
retv = *dest;
|
||||||
|
*dest = val;
|
||||||
|
_lwp_mutex_unlock( &interlocked_mutex );
|
||||||
|
return retv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *interlocked_xchg_ptr( void **dest, void *val )
|
||||||
|
{
|
||||||
|
long retv;
|
||||||
|
_lwp_mutex_lock( &interlocked_mutex );
|
||||||
|
retv = *dest;
|
||||||
|
*dest = val;
|
||||||
|
_lwp_mutex_unlock( &interlocked_mutex );
|
||||||
|
return retv;
|
||||||
|
}
|
||||||
|
|
||||||
|
long interlocked_xchg_add( long *dest, long incr )
|
||||||
|
{
|
||||||
|
long retv;
|
||||||
|
_lwp_mutex_lock( &interlocked_mutex );
|
||||||
|
retv = *dest;
|
||||||
|
*dest += incr;
|
||||||
|
_lwp_mutex_unlock( &interlocked_mutex );
|
||||||
|
return retv;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error You must implement the interlocked* functions for your CPU
|
||||||
|
#endif
|
Loading…
Reference in New Issue