《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 rivejä
7.3 KiB

12 vuotta sitten
  1. #ifndef __LIBS_ATOMIC_H__
  2. #define __LIBS_ATOMIC_H__
  3. /* Atomic operations that C can't guarantee us. Useful for resource counting etc.. */
  4. typedef struct {
  5. volatile int counter;
  6. } atomic_t;
  7. static inline int atomic_read(const atomic_t *v) __attribute__((always_inline));
  8. static inline void atomic_set(atomic_t *v, int i) __attribute__((always_inline));
  9. static inline void atomic_add(atomic_t *v, int i) __attribute__((always_inline));
  10. static inline void atomic_sub(atomic_t *v, int i) __attribute__((always_inline));
  11. static inline bool atomic_sub_test_zero(atomic_t *v, int i) __attribute__((always_inline));
  12. static inline void atomic_inc(atomic_t *v) __attribute__((always_inline));
  13. static inline void atomic_dec(atomic_t *v) __attribute__((always_inline));
  14. static inline bool atomic_inc_test_zero(atomic_t *v) __attribute__((always_inline));
  15. static inline bool atomic_dec_test_zero(atomic_t *v) __attribute__((always_inline));
  16. static inline int atomic_add_return(atomic_t *v, int i) __attribute__((always_inline));
  17. static inline int atomic_sub_return(atomic_t *v, int i) __attribute__((always_inline));
  18. /* *
  19. * atomic_read - read atomic variable
  20. * @v: pointer of type atomic_t
  21. *
  22. * Atomically reads the value of @v.
  23. * */
  24. static inline int
  25. atomic_read(const atomic_t *v) {
  26. return v->counter;
  27. }
  28. /* *
  29. * atomic_set - set atomic variable
  30. * @v: pointer of type atomic_t
  31. * @i: required value
  32. *
  33. * Atomically sets the value of @v to @i.
  34. * */
  35. static inline void
  36. atomic_set(atomic_t *v, int i) {
  37. v->counter = i;
  38. }
  39. /* *
  40. * atomic_add - add integer to atomic variable
  41. * @v: pointer of type atomic_t
  42. * @i: integer value to add
  43. *
  44. * Atomically adds @i to @v.
  45. * */
  46. static inline void
  47. atomic_add(atomic_t *v, int i) {
  48. asm volatile ("addl %1, %0" : "+m" (v->counter) : "ir" (i));
  49. }
  50. /* *
  51. * atomic_sub - subtract integer from atomic variable
  52. * @v: pointer of type atomic_t
  53. * @i: integer value to subtract
  54. *
  55. * Atomically subtracts @i from @v.
  56. * */
  57. static inline void
  58. atomic_sub(atomic_t *v, int i) {
  59. asm volatile("subl %1, %0" : "+m" (v->counter) : "ir" (i));
  60. }
  61. /* *
  62. * atomic_sub_test_zero - subtract value from variable and test result
  63. * @v: pointer of type atomic_t
  64. * @i: integer value to subtract
  65. *
  66. * Atomically subtracts @i from @v and
  67. * returns true if the result is zero, or false for all other cases.
  68. * */
  69. static inline bool
  70. atomic_sub_test_zero(atomic_t *v, int i) {
  71. unsigned char c;
  72. asm volatile("subl %2, %0; sete %1" : "+m" (v->counter), "=qm" (c) : "ir" (i) : "memory");
  73. return c != 0;
  74. }
  75. /* *
  76. * atomic_inc - increment atomic variable
  77. * @v: pointer of type atomic_t
  78. *
  79. * Atomically increments @v by 1.
  80. * */
  81. static inline void
  82. atomic_inc(atomic_t *v) {
  83. asm volatile("incl %0" : "+m" (v->counter));
  84. }
  85. /* *
  86. * atomic_dec - decrement atomic variable
  87. * @v: pointer of type atomic_t
  88. *
  89. * Atomically decrements @v by 1.
  90. * */
  91. static inline void
  92. atomic_dec(atomic_t *v) {
  93. asm volatile("decl %0" : "+m" (v->counter));
  94. }
  95. /* *
  96. * atomic_inc_test_zero - increment and test
  97. * @v: pointer of type atomic_t
  98. *
  99. * Atomically increments @v by 1 and
  100. * returns true if the result is zero, or false for all other cases.
  101. * */
  102. static inline bool
  103. atomic_inc_test_zero(atomic_t *v) {
  104. unsigned char c;
  105. asm volatile("incl %0; sete %1" : "+m" (v->counter), "=qm" (c) :: "memory");
  106. return c != 0;
  107. }
  108. /* *
  109. * atomic_dec_test_zero - decrement and test
  110. * @v: pointer of type atomic_t
  111. *
  112. * Atomically decrements @v by 1 and
  113. * returns true if the result is 0, or false for all other cases.
  114. * */
  115. static inline bool
  116. atomic_dec_test_zero(atomic_t *v) {
  117. unsigned char c;
  118. asm volatile("decl %0; sete %1" : "+m" (v->counter), "=qm" (c) :: "memory");
  119. return c != 0;
  120. }
  121. /* *
  122. * atomic_add_return - add integer and return
  123. * @i: integer value to add
  124. * @v: pointer of type atomic_t
  125. *
  126. * Atomically adds @i to @v and returns @i + @v
  127. * Requires Modern 486+ processor
  128. * */
  129. static inline int
  130. atomic_add_return(atomic_t *v, int i) {
  131. int __i = i;
  132. asm volatile("xaddl %0, %1" : "+r" (i), "+m" (v->counter) :: "memory");
  133. return i + __i;
  134. }
  135. /* *
  136. * atomic_sub_return - subtract integer and return
  137. * @v: pointer of type atomic_t
  138. * @i: integer value to subtract
  139. *
  140. * Atomically subtracts @i from @v and returns @v - @i
  141. * */
  142. static inline int
  143. atomic_sub_return(atomic_t *v, int i) {
  144. return atomic_add_return(v, -i);
  145. }
  146. static inline void set_bit(int nr, volatile void *addr) __attribute__((always_inline));
  147. static inline void clear_bit(int nr, volatile void *addr) __attribute__((always_inline));
  148. static inline void change_bit(int nr, volatile void *addr) __attribute__((always_inline));
  149. static inline bool test_and_set_bit(int nr, volatile void *addr) __attribute__((always_inline));
  150. static inline bool test_and_clear_bit(int nr, volatile void *addr) __attribute__((always_inline));
  151. static inline bool test_and_change_bit(int nr, volatile void *addr) __attribute__((always_inline));
  152. static inline bool test_bit(int nr, volatile void *addr) __attribute__((always_inline));
  153. /* *
  154. * set_bit - Atomically set a bit in memory
  155. * @nr: the bit to set
  156. * @addr: the address to start counting from
  157. *
  158. * Note that @nr may be almost arbitrarily large; this function is not
  159. * restricted to acting on a single-word quantity.
  160. * */
  161. static inline void
  162. set_bit(int nr, volatile void *addr) {
  163. asm volatile ("btsl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
  164. }
  165. /* *
  166. * clear_bit - Atomically clears a bit in memory
  167. * @nr: the bit to clear
  168. * @addr: the address to start counting from
  169. * */
  170. static inline void
  171. clear_bit(int nr, volatile void *addr) {
  172. asm volatile ("btrl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
  173. }
  174. /* *
  175. * change_bit - Atomically toggle a bit in memory
  176. * @nr: the bit to change
  177. * @addr: the address to start counting from
  178. * */
  179. static inline void
  180. change_bit(int nr, volatile void *addr) {
  181. asm volatile ("btcl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
  182. }
  183. /* *
  184. * test_and_set_bit - Atomically set a bit and return its old value
  185. * @nr: the bit to set
  186. * @addr: the address to count from
  187. * */
  188. static inline bool
  189. test_and_set_bit(int nr, volatile void *addr) {
  190. int oldbit;
  191. asm volatile ("btsl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory");
  192. return oldbit != 0;
  193. }
  194. /* *
  195. * test_and_clear_bit - Atomically clear a bit and return its old value
  196. * @nr: the bit to clear
  197. * @addr: the address to count from
  198. * */
  199. static inline bool
  200. test_and_clear_bit(int nr, volatile void *addr) {
  201. int oldbit;
  202. asm volatile ("btrl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory");
  203. return oldbit != 0;
  204. }
  205. /* *
  206. * test_and_change_bit - Atomically change a bit and return its old value
  207. * @nr: the bit to change
  208. * @addr: the address to count from
  209. * */
  210. static inline bool
  211. test_and_change_bit(int nr, volatile void *addr) {
  212. int oldbit;
  213. asm volatile ("btcl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory");
  214. return oldbit != 0;
  215. }
  216. /* *
  217. * test_bit - Determine whether a bit is set
  218. * @nr: the bit to test
  219. * @addr: the address to count from
  220. * */
  221. static inline bool
  222. test_bit(int nr, volatile void *addr) {
  223. int oldbit;
  224. asm volatile ("btl %2, %1; sbbl %0,%0" : "=r" (oldbit) : "m" (*(volatile long *)addr), "Ir" (nr));
  225. return oldbit != 0;
  226. }
  227. #endif /* !__LIBS_ATOMIC_H__ */