blob: 5b4d4a01f22c45746cd5a7f8ba75fc2095f9c0a3 [file] [log] [blame]
/** @file
A brief file description
@section license License
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.
*/
/****************************************************************************
ink_atomic.h
This file defines atomic memory operations.
On a Sparc V9, ink_atomic.c must be compiled with gcc and requires
the argument "-Wa,-xarch=v8plus" to get the assembler to emit V9
instructions.
****************************************************************************/
#pragma once
#include <cstdio>
#include <cstring>
#include <cstdint>
#include <cassert>
#include "tscore/ink_defs.h"
#include "tscore/ink_apidefs.h"
#include "tscore/ink_mutex.h"
/* GCC compiler >= 4.1 */
#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ >= 5))
/* see http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html */
// ink_atomic_swap(ptr, value)
// Writes @value into @ptr, returning the previous value.
template <typename T>
static inline T
ink_atomic_swap(T *mem, T value)
{
return __sync_lock_test_and_set(mem, value);
}
// ink_atomic_cas(mem, prev, next)
// Atomically store the value @next into the pointer @mem, but only if the current value at @mem is @prev.
// Returns true if @next was successfully stored.
template <typename T>
static inline bool
ink_atomic_cas(T *mem, T prev, T next)
{
return __sync_bool_compare_and_swap(mem, prev, next);
}
// ink_atomic_increment(ptr, count)
// Increment @ptr by @count, returning the previous value.
template <typename Type, typename Amount>
static inline Type
ink_atomic_increment(Type *mem, Amount count)
{
return __sync_fetch_and_add(mem, (Type)count);
}
// ink_atomic_decrement(ptr, count)
// Decrement @ptr by @count, returning the previous value.
template <typename Type, typename Amount>
static inline Type
ink_atomic_decrement(Type *mem, Amount count)
{
return __sync_fetch_and_sub(mem, (Type)count);
}
// Special hacks for ARM 32-bit
#if (defined(__arm__) || defined(__mips__)) && (SIZEOF_VOIDP == 4)
extern ink_mutex __global_death;
template <>
inline int64_t
ink_atomic_swap<int64_t>(int64_t *mem, int64_t value)
{
int64_t old;
ink_mutex_acquire(&__global_death);
old = *mem;
*mem = value;
ink_mutex_release(&__global_death);
return old;
}
template <>
inline bool
ink_atomic_cas<int64_t>(int64_t *mem, int64_t old, int64_t new_value)
{
int64_t curr;
ink_mutex_acquire(&__global_death);
curr = *mem;
if (old == curr)
*mem = new_value;
ink_mutex_release(&__global_death);
if (old == curr)
return 1;
return 0;
}
template <typename Amount>
static inline int64_t
ink_atomic_increment(int64_t *mem, Amount value)
{
int64_t curr;
ink_mutex_acquire(&__global_death);
curr = *mem;
*mem = curr + value;
ink_mutex_release(&__global_death);
return curr;
}
template <typename Amount>
static inline int64_t
ink_atomic_decrement(int64_t *mem, Amount value)
{
int64_t curr;
ink_mutex_acquire(&__global_death);
curr = *mem;
*mem = curr - value;
ink_mutex_release(&__global_death);
return curr;
}
template <typename Amount>
static inline uint64_t
ink_atomic_increment(uint64_t *mem, Amount value)
{
uint64_t curr;
ink_mutex_acquire(&__global_death);
curr = *mem;
*mem = curr + value;
ink_mutex_release(&__global_death);
return curr;
}
template <typename Amount>
static inline uint64_t
ink_atomic_decrement(uint64_t *mem, Amount value)
{
uint64_t curr;
ink_mutex_acquire(&__global_death);
curr = *mem;
*mem = curr - value;
ink_mutex_release(&__global_death);
return curr;
}
#endif /* Special hacks for ARM 32-bit */
/* not used for Intel Processors which have sequential(esque) consistency */
#define INK_WRITE_MEMORY_BARRIER
#define INK_MEMORY_BARRIER
#else /* not gcc > v4.1.2 */
#error Need a compiler / libc that supports atomic operations, e.g. gcc v4.1.2 or later
#endif