aboutsummaryrefslogtreecommitdiff
path: root/ubifs-utils/common/atomic.h
blob: f287d4355c34ffaaf6aa0f5ffa82aa15b278ddb2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//Source: http://golubenco.org/atomic-operations.html
#ifndef __ATOMIC_H__
#define __ATOMIC_H__

/* Check GCC version, just to be safe */
#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC_MINOR__ < 1)
# error atomic.h works only with GCC newer than version 4.1
#endif /* GNUC >= 4.1 */

/**
 * Atomic type.
 */
typedef struct {
	volatile long counter;
} atomic_long_t;

#define ATOMIC_INIT(i)  { (i) }

/**
 * Read atomic variable
 * @param v pointer of type atomic_long_t
 *
 * Atomically reads the value of @v.
 */
#define atomic_long_read(v) ((v)->counter)

/**
 * Set atomic variable
 * @param v pointer of type atomic_long_t
 * @param i required value
 */
#define atomic_long_set(v,i) (((v)->counter) = (i))

/**
 * Add to the atomic variable
 * @param i integer value to add
 * @param v pointer of type atomic_long_t
 */
static inline void atomic_long_add( int i, atomic_long_t *v )
{
	(void)__sync_add_and_fetch(&v->counter, i);
}

/**
 * Subtract the atomic variable
 * @param i integer value to subtract
 * @param v pointer of type atomic_long_t
 *
 * Atomically subtracts @i from @v.
 */
static inline void atomic_long_sub( int i, atomic_long_t *v )
{
	(void)__sync_sub_and_fetch(&v->counter, i);
}

/**
 * Subtract value from variable and test result
 * @param i integer value to subtract
 * @param v pointer of type atomic_long_t
 *
 * Atomically subtracts @i from @v and returns
 * true if the result is zero, or false for all
 * other cases.
 */
static inline int atomic_long_sub_and_test( int i, atomic_long_t *v )
{
	return !(__sync_sub_and_fetch(&v->counter, i));
}

/**
 * Increment atomic variable
 * @param v pointer of type atomic_long_t
 *
 * Atomically increments @v by 1.
 */
static inline void atomic_long_inc( atomic_long_t *v )
{
	(void)__sync_fetch_and_add(&v->counter, 1);
}

/**
 * @brief decrement atomic variable
 * @param v: pointer of type atomic_long_t
 *
 * Atomically decrements @v by 1.  Note that the guaranteed
 * useful range of an atomic_long_t is only 24 bits.
 */
static inline void atomic_long_dec( atomic_long_t *v )
{
	(void)__sync_fetch_and_sub(&v->counter, 1);
}

/**
 * @brief Decrement and test
 * @param v pointer of type atomic_long_t
 *
 * Atomically decrements @v by 1 and
 * returns true if the result is 0, or false for all other
 * cases.
 */
static inline int atomic_long_dec_and_test( atomic_long_t *v )
{
	return !(__sync_sub_and_fetch(&v->counter, 1));
}

/**
 * @brief Increment and test
 * @param v pointer of type atomic_long_t
 *
 * Atomically increments @v by 1
 * and returns true if the result is zero, or false for all
 * other cases.
 */
static inline int atomic_long_inc_and_test( atomic_long_t *v )
{
	return !(__sync_add_and_fetch(&v->counter, 1));
}

/**
 * @brief add and test if negative
 * @param v pointer of type atomic_long_t
 * @param i integer value to add
 *
 * Atomically adds @i to @v and returns true
 * if the result is negative, or false when
 * result is greater than or equal to zero.
 */
static inline int atomic_long_add_negative( int i, atomic_long_t *v )
{
	return (__sync_add_and_fetch(&v->counter, i) < 0);
}

#endif