11fb62fb0SOlivier Houchard /*
21fb62fb0SOlivier Houchard * Copyright 2010 Samy Al Bahra.
31fb62fb0SOlivier Houchard * All rights reserved.
41fb62fb0SOlivier Houchard *
51fb62fb0SOlivier Houchard * Redistribution and use in source and binary forms, with or without
61fb62fb0SOlivier Houchard * modification, are permitted provided that the following conditions
71fb62fb0SOlivier Houchard * are met:
81fb62fb0SOlivier Houchard * 1. Redistributions of source code must retain the above copyright
91fb62fb0SOlivier Houchard * notice, this list of conditions and the following disclaimer.
101fb62fb0SOlivier Houchard * 2. Redistributions in binary form must reproduce the above copyright
111fb62fb0SOlivier Houchard * notice, this list of conditions and the following disclaimer in the
121fb62fb0SOlivier Houchard * documentation and/or other materials provided with the distribution.
131fb62fb0SOlivier Houchard *
141fb62fb0SOlivier Houchard * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151fb62fb0SOlivier Houchard * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161fb62fb0SOlivier Houchard * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171fb62fb0SOlivier Houchard * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181fb62fb0SOlivier Houchard * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191fb62fb0SOlivier Houchard * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201fb62fb0SOlivier Houchard * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211fb62fb0SOlivier Houchard * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221fb62fb0SOlivier Houchard * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231fb62fb0SOlivier Houchard * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241fb62fb0SOlivier Houchard * SUCH DAMAGE.
251fb62fb0SOlivier Houchard */
261fb62fb0SOlivier Houchard
271fb62fb0SOlivier Houchard #ifndef CK_PR_GCC_H
281fb62fb0SOlivier Houchard #define CK_PR_GCC_H
291fb62fb0SOlivier Houchard
301fb62fb0SOlivier Houchard #ifndef CK_PR_H
311fb62fb0SOlivier Houchard #error Do not include this file directly, use ck_pr.h
321fb62fb0SOlivier Houchard #endif
331fb62fb0SOlivier Houchard
341fb62fb0SOlivier Houchard #include <ck_cc.h>
351fb62fb0SOlivier Houchard
361fb62fb0SOlivier Houchard CK_CC_INLINE static void
ck_pr_barrier(void)371fb62fb0SOlivier Houchard ck_pr_barrier(void)
381fb62fb0SOlivier Houchard {
391fb62fb0SOlivier Houchard
401fb62fb0SOlivier Houchard __asm__ __volatile__("" ::: "memory");
411fb62fb0SOlivier Houchard return;
421fb62fb0SOlivier Houchard }
431fb62fb0SOlivier Houchard
441fb62fb0SOlivier Houchard #ifndef CK_F_PR
451fb62fb0SOlivier Houchard #define CK_F_PR
461fb62fb0SOlivier Houchard
471fb62fb0SOlivier Houchard #include <ck_stdbool.h>
481fb62fb0SOlivier Houchard #include <ck_stdint.h>
491fb62fb0SOlivier Houchard
501fb62fb0SOlivier Houchard /*
511fb62fb0SOlivier Houchard * The following represent supported atomic operations.
521fb62fb0SOlivier Houchard * These operations may be emulated.
531fb62fb0SOlivier Houchard */
541fb62fb0SOlivier Houchard #include "ck_f_pr.h"
551fb62fb0SOlivier Houchard
561fb62fb0SOlivier Houchard #define CK_PR_ACCESS(x) (*(volatile __typeof__(x) *)&(x))
571fb62fb0SOlivier Houchard
581fb62fb0SOlivier Houchard #define CK_PR_LOAD(S, M, T) \
591fb62fb0SOlivier Houchard CK_CC_INLINE static T \
601fb62fb0SOlivier Houchard ck_pr_md_load_##S(const M *target) \
611fb62fb0SOlivier Houchard { \
621fb62fb0SOlivier Houchard T r; \
631fb62fb0SOlivier Houchard ck_pr_barrier(); \
641fb62fb0SOlivier Houchard r = CK_PR_ACCESS(*(const T *)target); \
651fb62fb0SOlivier Houchard ck_pr_barrier(); \
661fb62fb0SOlivier Houchard return (r); \
671fb62fb0SOlivier Houchard } \
681fb62fb0SOlivier Houchard CK_CC_INLINE static void \
691fb62fb0SOlivier Houchard ck_pr_md_store_##S(M *target, T v) \
701fb62fb0SOlivier Houchard { \
711fb62fb0SOlivier Houchard ck_pr_barrier(); \
721fb62fb0SOlivier Houchard CK_PR_ACCESS(*(T *)target) = v; \
731fb62fb0SOlivier Houchard ck_pr_barrier(); \
741fb62fb0SOlivier Houchard return; \
751fb62fb0SOlivier Houchard }
761fb62fb0SOlivier Houchard
771fb62fb0SOlivier Houchard CK_CC_INLINE static void *
ck_pr_md_load_ptr(const void * target)781fb62fb0SOlivier Houchard ck_pr_md_load_ptr(const void *target)
791fb62fb0SOlivier Houchard {
801fb62fb0SOlivier Houchard void *r;
811fb62fb0SOlivier Houchard
821fb62fb0SOlivier Houchard ck_pr_barrier();
83*271ce402SOlivier Houchard r = CK_CC_DECONST_PTR(*(volatile void *const*)(target));
841fb62fb0SOlivier Houchard ck_pr_barrier();
851fb62fb0SOlivier Houchard
861fb62fb0SOlivier Houchard return r;
871fb62fb0SOlivier Houchard }
881fb62fb0SOlivier Houchard
891fb62fb0SOlivier Houchard CK_CC_INLINE static void
ck_pr_md_store_ptr(void * target,const void * v)901fb62fb0SOlivier Houchard ck_pr_md_store_ptr(void *target, const void *v)
911fb62fb0SOlivier Houchard {
921fb62fb0SOlivier Houchard
931fb62fb0SOlivier Houchard ck_pr_barrier();
94*271ce402SOlivier Houchard *(volatile void **)target = CK_CC_DECONST_PTR(v);
951fb62fb0SOlivier Houchard ck_pr_barrier();
961fb62fb0SOlivier Houchard return;
971fb62fb0SOlivier Houchard }
981fb62fb0SOlivier Houchard
991fb62fb0SOlivier Houchard #define CK_PR_LOAD_S(S, T) CK_PR_LOAD(S, T, T)
1001fb62fb0SOlivier Houchard
CK_PR_LOAD_S(char,char)1011fb62fb0SOlivier Houchard CK_PR_LOAD_S(char, char)
1021fb62fb0SOlivier Houchard CK_PR_LOAD_S(uint, unsigned int)
1031fb62fb0SOlivier Houchard CK_PR_LOAD_S(int, int)
1048f87df16SOlivier Houchard #ifndef CK_PR_DISABLE_DOUBLE
1051fb62fb0SOlivier Houchard CK_PR_LOAD_S(double, double)
1068f87df16SOlivier Houchard #endif
1071fb62fb0SOlivier Houchard CK_PR_LOAD_S(64, uint64_t)
1081fb62fb0SOlivier Houchard CK_PR_LOAD_S(32, uint32_t)
1091fb62fb0SOlivier Houchard CK_PR_LOAD_S(16, uint16_t)
1101fb62fb0SOlivier Houchard CK_PR_LOAD_S(8, uint8_t)
1111fb62fb0SOlivier Houchard
1121fb62fb0SOlivier Houchard #undef CK_PR_LOAD_S
1131fb62fb0SOlivier Houchard #undef CK_PR_LOAD
1141fb62fb0SOlivier Houchard
1151fb62fb0SOlivier Houchard CK_CC_INLINE static void
1161fb62fb0SOlivier Houchard ck_pr_stall(void)
1171fb62fb0SOlivier Houchard {
1181fb62fb0SOlivier Houchard
1191fb62fb0SOlivier Houchard ck_pr_barrier();
1201fb62fb0SOlivier Houchard }
1211fb62fb0SOlivier Houchard
1221fb62fb0SOlivier Houchard /*
1231fb62fb0SOlivier Houchard * Load and store fences are equivalent to full fences in the GCC port.
1241fb62fb0SOlivier Houchard */
1251fb62fb0SOlivier Houchard #define CK_PR_FENCE(T) \
1261fb62fb0SOlivier Houchard CK_CC_INLINE static void \
1271fb62fb0SOlivier Houchard ck_pr_fence_strict_##T(void) \
1281fb62fb0SOlivier Houchard { \
1291fb62fb0SOlivier Houchard __sync_synchronize(); \
1301fb62fb0SOlivier Houchard }
1311fb62fb0SOlivier Houchard
1321fb62fb0SOlivier Houchard CK_PR_FENCE(atomic)
CK_PR_FENCE(atomic_atomic)1331fb62fb0SOlivier Houchard CK_PR_FENCE(atomic_atomic)
1341fb62fb0SOlivier Houchard CK_PR_FENCE(atomic_load)
1351fb62fb0SOlivier Houchard CK_PR_FENCE(atomic_store)
1361fb62fb0SOlivier Houchard CK_PR_FENCE(store_atomic)
1371fb62fb0SOlivier Houchard CK_PR_FENCE(load_atomic)
1381fb62fb0SOlivier Houchard CK_PR_FENCE(load)
1391fb62fb0SOlivier Houchard CK_PR_FENCE(load_load)
1401fb62fb0SOlivier Houchard CK_PR_FENCE(load_store)
1411fb62fb0SOlivier Houchard CK_PR_FENCE(store)
1421fb62fb0SOlivier Houchard CK_PR_FENCE(store_store)
1431fb62fb0SOlivier Houchard CK_PR_FENCE(store_load)
1441fb62fb0SOlivier Houchard CK_PR_FENCE(memory)
1451fb62fb0SOlivier Houchard CK_PR_FENCE(acquire)
1461fb62fb0SOlivier Houchard CK_PR_FENCE(release)
1471fb62fb0SOlivier Houchard CK_PR_FENCE(acqrel)
1481fb62fb0SOlivier Houchard CK_PR_FENCE(lock)
1491fb62fb0SOlivier Houchard CK_PR_FENCE(unlock)
1501fb62fb0SOlivier Houchard
1511fb62fb0SOlivier Houchard #undef CK_PR_FENCE
1521fb62fb0SOlivier Houchard
1531fb62fb0SOlivier Houchard /*
1541fb62fb0SOlivier Houchard * Atomic compare and swap.
1551fb62fb0SOlivier Houchard */
1561fb62fb0SOlivier Houchard #define CK_PR_CAS(S, M, T) \
1571fb62fb0SOlivier Houchard CK_CC_INLINE static bool \
1581fb62fb0SOlivier Houchard ck_pr_cas_##S(M *target, T compare, T set) \
1591fb62fb0SOlivier Houchard { \
1601fb62fb0SOlivier Houchard bool z; \
1611fb62fb0SOlivier Houchard z = __sync_bool_compare_and_swap((T *)target, compare, set); \
1621fb62fb0SOlivier Houchard return z; \
1631fb62fb0SOlivier Houchard }
1641fb62fb0SOlivier Houchard
1651fb62fb0SOlivier Houchard CK_PR_CAS(ptr, void, void *)
1661fb62fb0SOlivier Houchard
1671fb62fb0SOlivier Houchard #define CK_PR_CAS_S(S, T) CK_PR_CAS(S, T, T)
1681fb62fb0SOlivier Houchard
1691fb62fb0SOlivier Houchard CK_PR_CAS_S(char, char)
1701fb62fb0SOlivier Houchard CK_PR_CAS_S(int, int)
1711fb62fb0SOlivier Houchard CK_PR_CAS_S(uint, unsigned int)
1721fb62fb0SOlivier Houchard CK_PR_CAS_S(64, uint64_t)
1731fb62fb0SOlivier Houchard CK_PR_CAS_S(32, uint32_t)
1741fb62fb0SOlivier Houchard CK_PR_CAS_S(16, uint16_t)
1751fb62fb0SOlivier Houchard CK_PR_CAS_S(8, uint8_t)
1761fb62fb0SOlivier Houchard
1771fb62fb0SOlivier Houchard #undef CK_PR_CAS_S
1781fb62fb0SOlivier Houchard #undef CK_PR_CAS
1791fb62fb0SOlivier Houchard
1801fb62fb0SOlivier Houchard /*
1811fb62fb0SOlivier Houchard * Compare and swap, set *v to old value of target.
1821fb62fb0SOlivier Houchard */
1831fb62fb0SOlivier Houchard CK_CC_INLINE static bool
1841fb62fb0SOlivier Houchard ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *v)
1851fb62fb0SOlivier Houchard {
1861fb62fb0SOlivier Houchard set = __sync_val_compare_and_swap((void **)target, compare, set);
1871fb62fb0SOlivier Houchard *(void **)v = set;
1881fb62fb0SOlivier Houchard return (set == compare);
1891fb62fb0SOlivier Houchard }
1901fb62fb0SOlivier Houchard
1911fb62fb0SOlivier Houchard #define CK_PR_CAS_O(S, T) \
1921fb62fb0SOlivier Houchard CK_CC_INLINE static bool \
1931fb62fb0SOlivier Houchard ck_pr_cas_##S##_value(T *target, T compare, T set, T *v) \
1941fb62fb0SOlivier Houchard { \
1951fb62fb0SOlivier Houchard set = __sync_val_compare_and_swap(target, compare, set);\
1961fb62fb0SOlivier Houchard *v = set; \
1971fb62fb0SOlivier Houchard return (set == compare); \
1981fb62fb0SOlivier Houchard }
1991fb62fb0SOlivier Houchard
2001fb62fb0SOlivier Houchard CK_PR_CAS_O(char, char)
2011fb62fb0SOlivier Houchard CK_PR_CAS_O(int, int)
2021fb62fb0SOlivier Houchard CK_PR_CAS_O(uint, unsigned int)
2031fb62fb0SOlivier Houchard CK_PR_CAS_O(64, uint64_t)
2041fb62fb0SOlivier Houchard CK_PR_CAS_O(32, uint32_t)
2051fb62fb0SOlivier Houchard CK_PR_CAS_O(16, uint16_t)
2061fb62fb0SOlivier Houchard CK_PR_CAS_O(8, uint8_t)
2071fb62fb0SOlivier Houchard
2081fb62fb0SOlivier Houchard #undef CK_PR_CAS_O
2091fb62fb0SOlivier Houchard
2101fb62fb0SOlivier Houchard /*
2111fb62fb0SOlivier Houchard * Atomic fetch-and-add operations.
2121fb62fb0SOlivier Houchard */
2131fb62fb0SOlivier Houchard #define CK_PR_FAA(S, M, T) \
2141fb62fb0SOlivier Houchard CK_CC_INLINE static T \
2151fb62fb0SOlivier Houchard ck_pr_faa_##S(M *target, T d) \
2161fb62fb0SOlivier Houchard { \
2171fb62fb0SOlivier Houchard d = __sync_fetch_and_add((T *)target, d); \
2181fb62fb0SOlivier Houchard return (d); \
2191fb62fb0SOlivier Houchard }
2201fb62fb0SOlivier Houchard
2211fb62fb0SOlivier Houchard CK_PR_FAA(ptr, void, void *)
2221fb62fb0SOlivier Houchard
2231fb62fb0SOlivier Houchard #define CK_PR_FAA_S(S, T) CK_PR_FAA(S, T, T)
2241fb62fb0SOlivier Houchard
2251fb62fb0SOlivier Houchard CK_PR_FAA_S(char, char)
2261fb62fb0SOlivier Houchard CK_PR_FAA_S(uint, unsigned int)
2271fb62fb0SOlivier Houchard CK_PR_FAA_S(int, int)
2281fb62fb0SOlivier Houchard CK_PR_FAA_S(64, uint64_t)
2291fb62fb0SOlivier Houchard CK_PR_FAA_S(32, uint32_t)
2301fb62fb0SOlivier Houchard CK_PR_FAA_S(16, uint16_t)
2311fb62fb0SOlivier Houchard CK_PR_FAA_S(8, uint8_t)
2321fb62fb0SOlivier Houchard
2331fb62fb0SOlivier Houchard #undef CK_PR_FAA_S
2341fb62fb0SOlivier Houchard #undef CK_PR_FAA
2351fb62fb0SOlivier Houchard
2361fb62fb0SOlivier Houchard /*
2371fb62fb0SOlivier Houchard * Atomic store-only binary operations.
2381fb62fb0SOlivier Houchard */
2391fb62fb0SOlivier Houchard #define CK_PR_BINARY(K, S, M, T) \
2401fb62fb0SOlivier Houchard CK_CC_INLINE static void \
2411fb62fb0SOlivier Houchard ck_pr_##K##_##S(M *target, T d) \
2421fb62fb0SOlivier Houchard { \
2431fb62fb0SOlivier Houchard d = __sync_fetch_and_##K((T *)target, d); \
2441fb62fb0SOlivier Houchard return; \
2451fb62fb0SOlivier Houchard }
2461fb62fb0SOlivier Houchard
2471fb62fb0SOlivier Houchard #define CK_PR_BINARY_S(K, S, T) CK_PR_BINARY(K, S, T, T)
2481fb62fb0SOlivier Houchard
2491fb62fb0SOlivier Houchard #define CK_PR_GENERATE(K) \
2501fb62fb0SOlivier Houchard CK_PR_BINARY(K, ptr, void, void *) \
2511fb62fb0SOlivier Houchard CK_PR_BINARY_S(K, char, char) \
2521fb62fb0SOlivier Houchard CK_PR_BINARY_S(K, int, int) \
2531fb62fb0SOlivier Houchard CK_PR_BINARY_S(K, uint, unsigned int) \
2541fb62fb0SOlivier Houchard CK_PR_BINARY_S(K, 64, uint64_t) \
2551fb62fb0SOlivier Houchard CK_PR_BINARY_S(K, 32, uint32_t) \
2561fb62fb0SOlivier Houchard CK_PR_BINARY_S(K, 16, uint16_t) \
2571fb62fb0SOlivier Houchard CK_PR_BINARY_S(K, 8, uint8_t)
2581fb62fb0SOlivier Houchard
2591fb62fb0SOlivier Houchard CK_PR_GENERATE(add)
2601fb62fb0SOlivier Houchard CK_PR_GENERATE(sub)
2611fb62fb0SOlivier Houchard CK_PR_GENERATE(and)
2621fb62fb0SOlivier Houchard CK_PR_GENERATE(or)
2631fb62fb0SOlivier Houchard CK_PR_GENERATE(xor)
2641fb62fb0SOlivier Houchard
2651fb62fb0SOlivier Houchard #undef CK_PR_GENERATE
2661fb62fb0SOlivier Houchard #undef CK_PR_BINARY_S
2671fb62fb0SOlivier Houchard #undef CK_PR_BINARY
2681fb62fb0SOlivier Houchard
2691fb62fb0SOlivier Houchard #define CK_PR_UNARY(S, M, T) \
2701fb62fb0SOlivier Houchard CK_CC_INLINE static void \
2711fb62fb0SOlivier Houchard ck_pr_inc_##S(M *target) \
2721fb62fb0SOlivier Houchard { \
2731fb62fb0SOlivier Houchard ck_pr_add_##S(target, (T)1); \
2741fb62fb0SOlivier Houchard return; \
2751fb62fb0SOlivier Houchard } \
2761fb62fb0SOlivier Houchard CK_CC_INLINE static void \
2771fb62fb0SOlivier Houchard ck_pr_dec_##S(M *target) \
2781fb62fb0SOlivier Houchard { \
2791fb62fb0SOlivier Houchard ck_pr_sub_##S(target, (T)1); \
2801fb62fb0SOlivier Houchard return; \
2811fb62fb0SOlivier Houchard }
2821fb62fb0SOlivier Houchard
2831fb62fb0SOlivier Houchard #define CK_PR_UNARY_S(S, M) CK_PR_UNARY(S, M, M)
2841fb62fb0SOlivier Houchard
2851fb62fb0SOlivier Houchard CK_PR_UNARY(ptr, void, void *)
2861fb62fb0SOlivier Houchard CK_PR_UNARY_S(char, char)
2871fb62fb0SOlivier Houchard CK_PR_UNARY_S(int, int)
2881fb62fb0SOlivier Houchard CK_PR_UNARY_S(uint, unsigned int)
2891fb62fb0SOlivier Houchard CK_PR_UNARY_S(64, uint64_t)
2901fb62fb0SOlivier Houchard CK_PR_UNARY_S(32, uint32_t)
2911fb62fb0SOlivier Houchard CK_PR_UNARY_S(16, uint16_t)
2921fb62fb0SOlivier Houchard CK_PR_UNARY_S(8, uint8_t)
2931fb62fb0SOlivier Houchard
2941fb62fb0SOlivier Houchard #undef CK_PR_UNARY_S
2951fb62fb0SOlivier Houchard #undef CK_PR_UNARY
2961fb62fb0SOlivier Houchard #endif /* !CK_F_PR */
2971fb62fb0SOlivier Houchard #endif /* CK_PR_GCC_H */
298