root/headers/private/kernel/arch/x86/32/atomic.h
/*
 * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org.
 * Distributed under the terms of the MIT License.
 */
#ifndef _KERNEL_ARCH_X86_32_ATOMIC_H
#define _KERNEL_ARCH_X86_32_ATOMIC_H


static inline void
memory_read_barrier_inline(void)
{
        asm volatile("lock; addl $0, (%%esp)" : : : "memory");
}


static inline void
memory_write_barrier_inline(void)
{
        asm volatile("lock; addl $0, (%%esp)" : : : "memory");
}


static inline void
memory_full_barrier_inline(void)
{
        asm volatile("lock; addl $0, (%%esp)" : : : "memory");
}


#define memory_read_barrier             memory_read_barrier_inline
#define memory_write_barrier    memory_write_barrier_inline
#define memory_full_barrier             memory_full_barrier_inline


#if __GNUC__ < 4


static inline void
atomic_set_inline(int32* value, int32 newValue)
{
        memory_write_barrier();
        *(volatile int32*)value = newValue;
}


static inline int32
atomic_get_and_set_inline(int32* value, int32 newValue)
{
        asm volatile("xchgl %0, (%1)"
                : "+r" (newValue)
                : "r" (value)
                : "memory");
        return newValue;
}


static inline int32
atomic_test_and_set_inline(int32* value, int32 newValue, int32 testAgainst)
{
        asm volatile("lock; cmpxchgl %2, (%3)"
                : "=a" (newValue)
                : "0" (testAgainst), "r" (newValue), "r" (value)
                : "memory");
        return newValue;
}


static inline int32
atomic_add_inline(int32* value, int32 newValue)
{
        asm volatile("lock; xaddl %0, (%1)"
                : "+r" (newValue)
                : "r" (value)
                : "memory");
        return newValue;
}


static inline int32
atomic_get_inline(int32* value)
{
        int32 newValue = *(volatile int32*)value;
        memory_read_barrier();
        return newValue;
}


#define atomic_set                              atomic_set_inline
#define atomic_get_and_set              atomic_get_and_set_inline
#define atomic_test_and_set             atomic_test_and_set_inline
#define atomic_add                              atomic_add_inline
#define atomic_get                              atomic_get_inline


#endif  // dark ages


#endif  // _KERNEL_ARCH_X86_32_ATOMIC_H