at v3.16 4.5 kB view raw
1/* 2 * Generic C implementation of atomic counter operations. Usable on 3 * UP systems only. Do not include in machine independent code. 4 * 5 * Originally implemented for MN10300. 6 * 7 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 8 * Written by David Howells (dhowells@redhat.com) 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public Licence 12 * as published by the Free Software Foundation; either version 13 * 2 of the Licence, or (at your option) any later version. 14 */ 15#ifndef __ASM_GENERIC_ATOMIC_H 16#define __ASM_GENERIC_ATOMIC_H 17 18#include <asm/cmpxchg.h> 19#include <asm/barrier.h> 20 21#ifdef CONFIG_SMP 22/* Force people to define core atomics */ 23# if !defined(atomic_add_return) || !defined(atomic_sub_return) || \ 24 !defined(atomic_clear_mask) || !defined(atomic_set_mask) 25# error "SMP requires a little arch-specific magic" 26# endif 27#endif 28 29/* 30 * Atomic operations that C can't guarantee us. Useful for 31 * resource counting etc.. 32 */ 33 34#define ATOMIC_INIT(i) { (i) } 35 36#ifdef __KERNEL__ 37 38/** 39 * atomic_read - read atomic variable 40 * @v: pointer of type atomic_t 41 * 42 * Atomically reads the value of @v. 43 */ 44#ifndef atomic_read 45#define atomic_read(v) (*(volatile int *)&(v)->counter) 46#endif 47 48/** 49 * atomic_set - set atomic variable 50 * @v: pointer of type atomic_t 51 * @i: required value 52 * 53 * Atomically sets the value of @v to @i. 54 */ 55#define atomic_set(v, i) (((v)->counter) = (i)) 56 57#include <linux/irqflags.h> 58 59/** 60 * atomic_add_return - add integer to atomic variable 61 * @i: integer value to add 62 * @v: pointer of type atomic_t 63 * 64 * Atomically adds @i to @v and returns the result 65 */ 66#ifndef atomic_add_return 67static inline int atomic_add_return(int i, atomic_t *v) 68{ 69 unsigned long flags; 70 int temp; 71 72 raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ 73 temp = v->counter; 74 temp += i; 75 v->counter = temp; 76 raw_local_irq_restore(flags); 77 78 return temp; 79} 80#endif 81 82/** 83 * atomic_sub_return - subtract integer from atomic variable 84 * @i: integer value to subtract 85 * @v: pointer of type atomic_t 86 * 87 * Atomically subtracts @i from @v and returns the result 88 */ 89#ifndef atomic_sub_return 90static inline int atomic_sub_return(int i, atomic_t *v) 91{ 92 unsigned long flags; 93 int temp; 94 95 raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ 96 temp = v->counter; 97 temp -= i; 98 v->counter = temp; 99 raw_local_irq_restore(flags); 100 101 return temp; 102} 103#endif 104 105static inline int atomic_add_negative(int i, atomic_t *v) 106{ 107 return atomic_add_return(i, v) < 0; 108} 109 110static inline void atomic_add(int i, atomic_t *v) 111{ 112 atomic_add_return(i, v); 113} 114 115static inline void atomic_sub(int i, atomic_t *v) 116{ 117 atomic_sub_return(i, v); 118} 119 120static inline void atomic_inc(atomic_t *v) 121{ 122 atomic_add_return(1, v); 123} 124 125static inline void atomic_dec(atomic_t *v) 126{ 127 atomic_sub_return(1, v); 128} 129 130#define atomic_dec_return(v) atomic_sub_return(1, (v)) 131#define atomic_inc_return(v) atomic_add_return(1, (v)) 132 133#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) 134#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) 135#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) 136 137#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) 138#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) 139 140static inline int __atomic_add_unless(atomic_t *v, int a, int u) 141{ 142 int c, old; 143 c = atomic_read(v); 144 while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) 145 c = old; 146 return c; 147} 148 149/** 150 * atomic_clear_mask - Atomically clear bits in atomic variable 151 * @mask: Mask of the bits to be cleared 152 * @v: pointer of type atomic_t 153 * 154 * Atomically clears the bits set in @mask from @v 155 */ 156#ifndef atomic_clear_mask 157static inline void atomic_clear_mask(unsigned long mask, atomic_t *v) 158{ 159 unsigned long flags; 160 161 mask = ~mask; 162 raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ 163 v->counter &= mask; 164 raw_local_irq_restore(flags); 165} 166#endif 167 168/** 169 * atomic_set_mask - Atomically set bits in atomic variable 170 * @mask: Mask of the bits to be set 171 * @v: pointer of type atomic_t 172 * 173 * Atomically sets the bits set in @mask in @v 174 */ 175#ifndef atomic_set_mask 176static inline void atomic_set_mask(unsigned int mask, atomic_t *v) 177{ 178 unsigned long flags; 179 180 raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ 181 v->counter |= mask; 182 raw_local_irq_restore(flags); 183} 184#endif 185 186#endif /* __KERNEL__ */ 187#endif /* __ASM_GENERIC_ATOMIC_H */