MentOS  0.8.0
The Mentoring Operating System
stdatomic.h
Go to the documentation of this file.
1 
6 #pragma once
7 
8 #include "klib/compiler.h"
9 
12 typedef volatile unsigned atomic_t;
13 
15 #define LOCK_PREFIX "\n\tlock; "
16 
18 #define barrier() __asm__ __volatile__("" \
19  : \
20  : \
21  : "memory")
22 
24 #define cpu_relax() __asm__ __volatile__("pause\n" \
25  : \
26  : \
27  : "memory")
28 
33 inline static int atomic_set_and_test(atomic_t *ptr, int value)
34 {
35  // The + in "+r" and "+m" denotes a read-modify-write operand.
36  __asm__ __volatile__(LOCK_PREFIX // Lock
37  "xchgl %0, %1" // Instruction
38  : "+r"(value), "+m"(*ptr) // Input + Output
39  : // No input-only
40  : "memory"); // Side effects
41  return value;
42 }
43 
47 inline static void atomic_set(atomic_t *ptr, int value)
48 {
49  atomic_set_and_test(ptr, value);
50 }
51 
55 inline static int atomic_read(const atomic_t *ptr)
56 {
57  return READ_ONCE(*ptr);
58 }
59 
64 inline static int atomic_add(atomic_t *ptr, int value)
65 {
66  // The + in "+r" and "+m" denotes a read-modify-write operand.
67  __asm__ __volatile__(LOCK_PREFIX // Lock
68  "xaddl %0, %1" // Instruction
69  : "+r"(value), "+m"(*ptr) // Input + Output
70  : // No input-only
71  : "memory"); // Side effects
72  return value;
73 }
74 
79 inline static int atomic_sub(atomic_t *ptr, int value)
80 {
81  return atomic_add(ptr, -value);
82 }
83 
87 inline static int atomic_inc(atomic_t *ptr)
88 {
89  return atomic_add(ptr, 1);
90 }
91 
95 inline static int atomic_dec(atomic_t *ptr)
96 {
97  return atomic_add(ptr, -1);
98 }
99 
104 inline static int atomic_add_negative(atomic_t *ptr, int value)
105 {
106  return atomic_add(ptr, value) < 0;
107 }
108 
113 inline static int atomic_sub_and_test(atomic_t *ptr, int value)
114 {
115  return atomic_sub(ptr, value) == 0;
116 }
117 
121 inline static int atomic_inc_and_test(atomic_t *ptr)
122 {
123  return atomic_inc(ptr) == 0;
124 }
125 
129 inline static int atomic_dec_and_test(atomic_t *ptr)
130 {
131  return atomic_dec(ptr) == 0;
132 }
133 
137 static inline void set_bit(int offset, volatile unsigned long *base)
138 {
139  __asm__ __volatile__("btsl %[offset], %[base]"
140  : [base] "=m"(*(volatile long *)base)
141  : [offset] "Ir"(offset));
142 }
143 
147 static inline void clear_bit(int offset, volatile unsigned long *base)
148 {
149  __asm__ __volatile__("btrl %[offset],%[base]"
150  : [base] "=m"(*(volatile long *)base)
151  : [offset] "Ir"(offset));
152 }
153 
158 static inline int test_bit(int offset, volatile unsigned long *base)
159 {
160  int old = 0;
161  __asm__ __volatile__("btl %[offset],%[base]\n" // Bit Test
162  "sbbl %[old],%[old]\n" // Return the previous value.
163  : [old] "=r"(old)
164  : [base] "m"(*(volatile long *)base),
165  [offset] "Ir"(offset));
166  return old;
167 }
168 
169 // == Volatile Variable =======================================================
170 // In C, and consequently C++, the volatile keyword was intended to:
171 // - allow access to memory-mapped I/O devices
172 // - allow uses of variables between setjmp and longjmp
173 // - allow uses of sig_atomic_t variables in signal handlers.
174 //
175 // Operations on volatile variables are not atomic, nor do they establish
176 // a proper happens-before relationship for threading like with the
177 // `__asm__` inline blocks.
178 // This is specified in the relevant standards (C, C++, POSIX, WIN32), and
179 // volatile variables are not thread-safe in the vast majority of current
180 // implementations.
181 // Thus, the usage of volatile keyword as a portable synchronization mechanism
182 // is discouraged by many C/C++ groups.
183 
184 // == xchg/xchgl ==============================================================
Definition of memory barriers.
#define READ_ONCE(var)
Read the value from the given variable.
Definition: compiler.h:48
static void set_bit(int offset, volatile unsigned long *base)
Atomically sets a bit in memory, using Bit Test And Set (bts).
Definition: stdatomic.h:137
volatile unsigned atomic_t
Standard structure for atomic operations (see below for volatile explanation).
Definition: stdatomic.h:12
static void atomic_set(atomic_t *ptr, int value)
Atomically set the value pointed by ptr to value.
Definition: stdatomic.h:47
static int atomic_read(const atomic_t *ptr)
Atomically read the value pointed by ptr.
Definition: stdatomic.h:55
static int atomic_inc_and_test(atomic_t *ptr)
Atomically increment ptr and checks if the result is zero.
Definition: stdatomic.h:121
static int atomic_add_negative(atomic_t *ptr, int value)
Atomically add value to ptr and checks if the result is negative.
Definition: stdatomic.h:104
static int atomic_sub_and_test(atomic_t *ptr, int value)
Atomically subtract value from ptr and checks if the result is zero.
Definition: stdatomic.h:113
static int atomic_set_and_test(atomic_t *ptr, int value)
Atomically sets value at ptr.
Definition: stdatomic.h:33
static int atomic_dec(atomic_t *ptr)
Atomically decrement the value at ptr.
Definition: stdatomic.h:95
static void clear_bit(int offset, volatile unsigned long *base)
Atomically clears a bit in memory.
Definition: stdatomic.h:147
static int atomic_add(atomic_t *ptr, int value)
Atomically add value to the value pointed by ptr.
Definition: stdatomic.h:64
static int atomic_inc(atomic_t *ptr)
Atomically increment the value at ptr.
Definition: stdatomic.h:87
#define LOCK_PREFIX
The prefix used to lock.
Definition: stdatomic.h:15
static int atomic_sub(atomic_t *ptr, int value)
Atomically subtract value from the value pointed by ptr.
Definition: stdatomic.h:79
static int atomic_dec_and_test(atomic_t *ptr)
Atomically decrement ptr and checks if the result is zero.
Definition: stdatomic.h:129
static int test_bit(int offset, volatile unsigned long *base)
Atomically tests a bit in memory.
Definition: stdatomic.h:158