blob: e528d18f2103940d4a07e5bead4d1220aecee726 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Intel, Evgueni Brevnov
*/
#ifndef _PORT_ATOMIC_H_
#define _PORT_ATOMIC_H_
/**
* @file
* Atomic operations
*/
#include "open/types.h"
#include "port_general.h"
/**
* @defgroup port_atomic Atomic operations
*
* All atomic operations are perfomance critical,
* thus they are defined as inlined for most platforms in this file.
* @ingroup port_apr
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_IPF_) || defined(DOXYGEN)
/**
* The atomic compare and exchange operation on <code>U_8</code>.
* The function compares the current value of the specified <i>data</i>
* with the <i>comp</i> value and if they match, swaps the <i>data</i>
* with the <i>value</i>.
* @param[in, out] data - the pointer to the value
* @param[in] value - the new value
* @param[in] comp - the value to compare with
* @return The old value.
*/
APR_DECLARE(U_8) port_atomic_cas8(volatile U_8 * data,
U_8 value, U_8 comp);
/**
* The atomic compare and exchange operation on uint16.
* The function compares the current value of the specified <i>data</i>
* with the <i>comp</i> value and if they match, swaps the <i>data</i>
* with the <i>value</i>.
* @param[in, out] data - the pointer to the value
* @param[in] value - the new value
* @param[in] comp - the value to compare with
* @return The old value.
*/
APR_DECLARE(uint16) port_atomic_cas16(volatile uint16 * data,
uint16 value, uint16 comp);
/**
* The atomic compare and exchange operation on uint64.
* The function compares the current value of the specified <i>data</i>
* with the <i>comp</i> value and if they match, swaps the <i>data</i>
* with the <i>value</i>.
* @param[in, out] data - the pointer to the value
* @param[in] value - the new value
* @param[in] comp - the value to compare with
* @return The old value.
*/
APR_DECLARE(uint64) port_atomic_cas64(volatile uint64 * data,
uint64 value, uint64 comp);
/**
* The atomic compare and exchange operation on a pointer.
* The function compares the current value of the specified <i>data</i>
* with the <i>comp</i> value and if they match, swaps the <i>data</i>
* with the <i>value</i>.
* @param[in, out] data - the pointer to the value
* @param[in] value - the new value
* @param[in] comp - the value to compare with
* @return The old value.
*/
APR_DECLARE(void *) port_atomic_casptr(volatile void ** data,
void * value, const void * comp);
/** @} */
#elif defined(_WIN32) && !defined(_WIN64)
PORT_INLINE U_8 port_atomic_cas8(volatile U_8 * data , U_8 value, U_8 comp) {
__asm {
mov al, comp
mov dl, value
mov ecx, data
lock cmpxchg [ecx], dl
mov comp, al
}
return comp;
}
PORT_INLINE uint16 port_atomic_cas16(volatile uint16 * data , uint16 value, uint16 comp) {
__asm {
mov ax, comp
mov dx, value
mov ecx, data
lock cmpxchg [ecx], dx
mov comp, ax
}
return comp;
}
PORT_INLINE uint64 port_atomic_cas64(volatile uint64 * data , uint64 value, uint64 comp) {
__asm {
lea esi, comp
mov eax, [esi]
mov edx, [esi] + 4
lea esi, value
mov ebx, [esi]
mov ecx, [esi] + 4
mov esi, data
lock cmpxchg8b [esi]
lea esi, comp
mov [esi], eax
mov [esi] + 4, edx
}
return comp;
}
PORT_INLINE void * port_atomic_casptr(volatile void ** data, void * value, const void * comp) {
return InterlockedCompareExchangePointer((volatile PVOID *) data, value, (PVOID) comp);
}
#elif defined(HYX86_64) && defined (_WIN64)
#pragma intrinsic(_InterlockedCompareExchange16)
#pragma intrinsic(_InterlockedCompareExchange64)
PORT_INLINE U_8 port_atomic_cas8(volatile U_8 * data,
U_8 value, U_8 comp);
PORT_INLINE uint16 port_atomic_cas16(volatile uint16 * data,
uint16 value, uint16 comp)
{
return _InterlockedCompareExchange16((volatile SHORT *)data, value, comp);
}
PORT_INLINE uint64 port_atomic_cas64(volatile uint64 * data,
uint64 value, uint64 comp)
{
return _InterlockedCompareExchange64((volatile LONG64 *)data, value, comp);
}
PORT_INLINE void * port_atomic_casptr(volatile void ** data, void * value, const void * comp) {
return InterlockedCompareExchangePointer((volatile PVOID *) data, value, (PVOID) comp);
}
#elif defined (PLATFORM_POSIX)
PORT_INLINE U_8 port_atomic_cas8(volatile U_8 * data , U_8 value, U_8 comp) {
#if defined(HYX86) || defined(HYX86_64)
__asm__ __volatile__(
"lock cmpxchgb %1, (%2)"
:"=a"(comp)
:"d"(value), "r"(data), "0"(comp)
);
return comp;
#else
ABORT("Not supported");
#endif
}
PORT_INLINE uint16 port_atomic_cas16(volatile uint16 * data , uint16 value, uint16 comp) {
uint16 ret;
#if defined(HYX86) || defined(HYX86_64)
__asm__ __volatile__(
"lock cmpxchgw %w1, %2"
:"=a"(ret)
:"q"(value), "m"(*data), "0"(comp)
: "memory"
);
return ret;
#else
ABORT("Not supported");
#endif
}
PORT_INLINE uint64 port_atomic_cas64(volatile uint64 * data , uint64 value, uint64 comp) {
#if defined(HYX86)
__asm__ __volatile__(
"push %%ebx;\n\t"
"lea %0, %%esi;\n\t"
"mov (%%esi), %%eax;\n\t"
"mov 4(%%esi), %%edx;\n\t"
"lea %1, %%esi;\n\t"
"mov (%%esi), %%ebx;\n\t"
"mov 4(%%esi), %%ecx;\n\t"
"mov %2, %%esi;\n\t"
"lock cmpxchg8b (%%esi);\n\t"
"lea %0, %%esi;\n\t"
"mov %%eax, (%%esi);\n\t"
"mov %%edx, 4(%%esi);\n\t"
"pop %%ebx"
: /* no outputs (why not comp?)*/
:"m"(comp), "m"(value), "m"(data) /* inputs */
:"%eax", "%ecx", "%edx", "%esi", "memory" /* clobbers */
);
return comp;
#elif defined(HYX86_64) // defined(HYX86)
__asm__ __volatile__(
"lock cmpxchgq %1, (%2)"
:"=a"(comp) /* outputs */
:"d"(value), "r"(data), "a"(comp)
);
return comp;
#else
ABORT("Not supported");
#endif
}
PORT_INLINE void * port_atomic_casptr(volatile void ** data, void * value, const void * comp) {
#if defined(HYX86)
U_32 Exchange = (U_32)value;
U_32 Comperand = (U_32)comp;
__asm__ __volatile__(
"lock cmpxchgl %1, (%2)"
:"=a"(Comperand)
:"d"(Exchange), "r"(data), "a"(Comperand)
);
return (void*)Comperand;
#elif defined(HYX86_64) // defined(HYX86)
uint64 Exchange = (uint64)value;
uint64 Comperand = (uint64)comp;
__asm__(
"lock cmpxchgq %1, (%2)"
:"=a"(Comperand)
:"d"(Exchange), "r"(data), "a"(Comperand)
);
return (void *)Comperand;
#else // defined(HYX86_64)
ABORT("Not supported");
#endif
}
#endif //defined (POSIX)
#ifdef __cplusplus
}
#endif
#endif /* _PORT_ATOMIC_H_ */