1 /*****************************************************************************/
4 * \brief atomic operations header and generic implementations
5 * \ingroup l4util_atomic
8 * \author Lars Reuther <reuther@os.inf.tu-dresden.de>,
9 * Jork Loeser <jork@os.inf.tu-dresden.de> */
11 * (c) 2000-2009 Technische Universität Dresden
12 * This file is part of TUD:OS and distributed under the terms of the
13 * GNU Lesser General Public License 2.1.
14 * Please see the COPYING-LGPL-2.1 file for details.
17 /*****************************************************************************/
18 #ifndef __L4UTIL__INCLUDE__ATOMIC_H__
19 #define __L4UTIL__INCLUDE__ATOMIC_H__
21 #include <l4/sys/l4int.h>
22 #include <l4/sys/compiler.h>
24 /*****************************************************************************
26 *****************************************************************************/
31 * \defgroup l4util_atomic Atomic Instructions
36 * \brief Atomic compare and exchange (64 bit version)
37 * \ingroup l4util_atomic
39 * \param dest destination operand
40 * \param cmp_val compare value
41 * \param new_val new value for dest
43 * \return 0 if comparison failed, 1 otherwise
45 * Compare the value in \em dest with \em cmp_val, if equal set \em dest to
49 l4util_cmpxchg64(volatile l4_uint64_t * dest,
50 l4_uint64_t cmp_val, l4_uint64_t new_val);
53 * \brief Atomic compare and exchange (32 bit version)
54 * \ingroup l4util_atomic
56 * \param dest destination operand
57 * \param cmp_val compare value
58 * \param new_val new value for dest
60 * \return 0 if comparison failed, !=0 otherwise
62 * Compare the value in \em dest with \em cmp_val, if equal set \em dest to
66 l4util_cmpxchg32(volatile l4_uint32_t * dest,
67 l4_uint32_t cmp_val, l4_uint32_t new_val);
70 * \brief Atomic compare and exchange (16 bit version)
71 * \ingroup l4util_atomic
73 * \param dest destination operand
74 * \param cmp_val compare value
75 * \param new_val new value for dest
77 * \return 0 if comparison failed, !=0 otherwise
79 * Compare the value in \em dest with \em cmp_val, if equal set \em dest to
83 l4util_cmpxchg16(volatile l4_uint16_t * dest,
84 l4_uint16_t cmp_val, l4_uint16_t new_val);
87 * \brief Atomic compare and exchange (8 bit version)
88 * \ingroup l4util_atomic
90 * \param dest destination operand
91 * \param cmp_val compare value
92 * \param new_val new value for dest
94 * \return 0 if comparison failed, !=0 otherwise
96 * Compare the value in \em dest with \em cmp_val, if equal set \em dest to
100 l4util_cmpxchg8(volatile l4_uint8_t * dest,
101 l4_uint8_t cmp_val, l4_uint8_t new_val);
104 * \brief Atomic compare and exchange (machine wide fields)
105 * \ingroup l4util_atomic
107 * \param dest destination operand
108 * \param cmp_val compare value
109 * \param new_val new value for dest
111 * \return 0 if comparison failed, 1 otherwise
113 * Compare the value in \em dest with \em cmp_val, if equal set \em dest to
117 l4util_cmpxchg(volatile l4_umword_t * dest,
118 l4_umword_t cmp_val, l4_umword_t new_val);
121 * \brief Atomic exchange (32 bit version)
122 * \ingroup l4util_atomic
124 * \param dest destination operand
125 * \param val new value for dest
127 * \return old value at destination
129 L4_INLINE l4_uint32_t
130 l4util_xchg32(volatile l4_uint32_t * dest, l4_uint32_t val);
133 * \brief Atomic exchange (16 bit version)
134 * \ingroup l4util_atomic
136 * \param dest destination operand
137 * \param val new value for dest
139 * \return old value at destination
141 L4_INLINE l4_uint16_t
142 l4util_xchg16(volatile l4_uint16_t * dest, l4_uint16_t val);
145 * \brief Atomic exchange (8 bit version)
146 * \ingroup l4util_atomic
148 * \param dest destination operand
149 * \param val new value for dest
151 * \return old value at destination
154 l4util_xchg8(volatile l4_uint8_t * dest, l4_uint8_t val);
157 * \brief Atomic exchange (machine wide fields)
158 * \ingroup l4util_atomic
160 * \param dest destination operand
161 * \param val new value for dest
163 * \return old value at destination
165 L4_INLINE l4_umword_t
166 l4util_xchg(volatile l4_umword_t * dest, l4_umword_t val);
168 //!@name Atomic add/sub/and/or (8,16,32 bit version) without result
170 * \ingroup l4util_atomic
172 * \param dest destination operand
173 * \param val value to add/sub/and/or
176 l4util_add8(volatile l4_uint8_t *dest, l4_uint8_t val);
178 l4util_add16(volatile l4_uint16_t *dest, l4_uint16_t val);
180 l4util_add32(volatile l4_uint32_t *dest, l4_uint32_t val);
182 l4util_sub8(volatile l4_uint8_t *dest, l4_uint8_t val);
184 l4util_sub16(volatile l4_uint16_t *dest, l4_uint16_t val);
186 l4util_sub32(volatile l4_uint32_t *dest, l4_uint32_t val);
188 l4util_and8(volatile l4_uint8_t *dest, l4_uint8_t val);
190 l4util_and16(volatile l4_uint16_t *dest, l4_uint16_t val);
192 l4util_and32(volatile l4_uint32_t *dest, l4_uint32_t val);
194 l4util_or8(volatile l4_uint8_t *dest, l4_uint8_t val);
196 l4util_or16(volatile l4_uint16_t *dest, l4_uint16_t val);
198 l4util_or32(volatile l4_uint32_t *dest, l4_uint32_t val);
201 //!@name Atomic add/sub/and/or operations (8,16,32 bit) with result
203 * \ingroup l4util_atomic
205 * \param dest destination operand
206 * \param val value to add/sub/and/or
210 l4util_add8_res(volatile l4_uint8_t *dest, l4_uint8_t val);
211 L4_INLINE l4_uint16_t
212 l4util_add16_res(volatile l4_uint16_t *dest, l4_uint16_t val);
213 L4_INLINE l4_uint32_t
214 l4util_add32_res(volatile l4_uint32_t *dest, l4_uint32_t val);
216 l4util_sub8_res(volatile l4_uint8_t *dest, l4_uint8_t val);
217 L4_INLINE l4_uint16_t
218 l4util_sub16_res(volatile l4_uint16_t *dest, l4_uint16_t val);
219 L4_INLINE l4_uint32_t
220 l4util_sub32_res(volatile l4_uint32_t *dest, l4_uint32_t val);
222 l4util_and8_res(volatile l4_uint8_t *dest, l4_uint8_t val);
223 L4_INLINE l4_uint16_t
224 l4util_and16_res(volatile l4_uint16_t *dest, l4_uint16_t val);
225 L4_INLINE l4_uint32_t
226 l4util_and32_res(volatile l4_uint32_t *dest, l4_uint32_t val);
228 l4util_or8_res(volatile l4_uint8_t *dest, l4_uint8_t val);
229 L4_INLINE l4_uint16_t
230 l4util_or16_res(volatile l4_uint16_t *dest, l4_uint16_t val);
231 L4_INLINE l4_uint32_t
232 l4util_or32_res(volatile l4_uint32_t *dest, l4_uint32_t val);
235 //!@name Atomic inc/dec (8,16,32 bit) without result
237 * \ingroup l4util_atomic
239 * \param dest destination operand
242 l4util_inc8(volatile l4_uint8_t *dest);
244 l4util_inc16(volatile l4_uint16_t *dest);
246 l4util_inc32(volatile l4_uint32_t *dest);
248 l4util_dec8(volatile l4_uint8_t *dest);
250 l4util_dec16(volatile l4_uint16_t *dest);
252 l4util_dec32(volatile l4_uint32_t *dest);
255 //!@name Atomic inc/dec (8,16,32 bit) with result
257 * \ingroup l4util_atomic
259 * \param dest destination operand
263 l4util_inc8_res(volatile l4_uint8_t *dest);
264 L4_INLINE l4_uint16_t
265 l4util_inc16_res(volatile l4_uint16_t *dest);
266 L4_INLINE l4_uint32_t
267 l4util_inc32_res(volatile l4_uint32_t *dest);
269 l4util_dec8_res(volatile l4_uint8_t *dest);
270 L4_INLINE l4_uint16_t
271 l4util_dec16_res(volatile l4_uint16_t *dest);
272 L4_INLINE l4_uint32_t
273 l4util_dec32_res(volatile l4_uint32_t *dest);
278 * \ingroup l4util_atomic
280 * \param dest destination operand
281 * \param val value to add
284 l4util_atomic_add(volatile long *dest, long val);
287 * \brief Atomic increment
288 * \ingroup l4util_atomic
290 * \param dest destination operand
293 l4util_atomic_inc(volatile long *dest);
297 /*****************************************************************************
298 *** Get architecture specific implementations
299 *****************************************************************************/
300 #include <l4/util/atomic_arch.h>
302 /*****************************************************************************
303 *** Generic implementation
304 *** (make sure to prevent page faults between critical sections)
305 *** Do not use those functions, go implement a version for your
307 *****************************************************************************/
311 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_CMPXCHG16
312 #include <l4/util/irq.h>
315 l4util_cmpxchg16(volatile l4_uint16_t * dest,
316 l4_uint16_t cmp_val, l4_uint16_t new_val)
322 if (*dest == cmp_val)
334 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_CMPXCHG32
335 #include <l4/util/irq.h>
338 l4util_cmpxchg32(volatile l4_uint32_t * dest,
339 l4_uint32_t cmp_val, l4_uint32_t new_val)
345 if (*dest == cmp_val)
357 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_CMPXCHG
358 #include <l4/util/irq.h>
361 l4util_cmpxchg(volatile l4_umword_t * dest,
362 l4_umword_t cmp_val, l4_umword_t new_val)
368 if (*dest == cmp_val)
380 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_XCHG32
381 #include <l4/util/irq.h>
383 L4_INLINE l4_uint32_t
384 l4util_xchg32(volatile l4_uint32_t * dest, l4_uint32_t val)
399 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_XCHG
400 #include <l4/util/irq.h>
402 L4_INLINE l4_umword_t
403 l4util_xchg(volatile l4_umword_t * dest, l4_umword_t val)
418 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_ADD
419 #include <l4/util/irq.h>
422 l4util_atomic_add(volatile long *dest, long val)
430 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_INC
431 #include <l4/util/irq.h>
434 l4util_atomic_inc(volatile long *dest)
443 /* Non-implemented version, catch with a linker warning */
445 extern int __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(void);
447 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_INC8
449 l4util_inc8(volatile l4_uint8_t *dest)
450 { (void)dest; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
453 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_INC16
455 l4util_inc16(volatile l4_uint16_t *dest)
456 { (void)dest; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
459 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_DEC8
461 l4util_dec8(volatile l4_uint8_t *dest)
462 { (void)dest; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
465 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_DEC16
467 l4util_dec16(volatile l4_uint16_t *dest)
468 { (void)dest; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
473 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_INC8_RES
475 l4util_inc8_res(volatile l4_uint8_t *dest)
476 { (void)dest; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
479 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_INC16_RES
480 L4_INLINE l4_uint16_t
481 l4util_inc16_res(volatile l4_uint16_t *dest)
482 { (void)dest; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
485 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_DEC8_RES
487 l4util_dec8_res(volatile l4_uint8_t *dest)
488 { (void)dest; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
491 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_DEC16_RES
492 L4_INLINE l4_uint16_t
493 l4util_dec16_res(volatile l4_uint16_t *dest)
494 { (void)dest; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
497 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_CMPXCHG64
499 l4util_cmpxchg64(volatile l4_uint64_t * dest,
500 l4_uint64_t cmp_val, l4_uint64_t new_val)
501 { (void)dest; (void)cmp_val; (void)new_val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
504 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_CMPXCHG8
506 l4util_cmpxchg8(volatile l4_uint8_t * dest,
507 l4_uint8_t cmp_val, l4_uint8_t new_val)
508 { (void)dest; (void)cmp_val; (void)new_val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
511 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_CMPXCHG
513 l4util_cmpxchg(volatile l4_umword_t * dest,
514 l4_umword_t cmp_val, l4_umword_t new_val)
515 { (void)dest; (void)cmp_val; (void)new_val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
518 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_XCHG16
519 L4_INLINE l4_uint16_t
520 l4util_xchg16(volatile l4_uint16_t * dest, l4_uint16_t val)
521 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
524 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_XCHG8
526 l4util_xchg8(volatile l4_uint8_t * dest, l4_uint8_t val)
527 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0; }
531 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_ADD8
533 l4util_add8(volatile l4_uint8_t *dest, l4_uint8_t val)
534 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
537 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_ADD16
539 l4util_add16(volatile l4_uint16_t *dest, l4_uint16_t val)
540 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
543 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_ADD32
545 l4util_add32(volatile l4_uint32_t *dest, l4_uint32_t val)
546 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
550 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_SUB8
552 l4util_sub8(volatile l4_uint8_t *dest, l4_uint8_t val)
553 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
556 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_SUB16
558 l4util_sub16(volatile l4_uint16_t *dest, l4_uint16_t val)
559 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
562 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_SUB32
564 l4util_sub32(volatile l4_uint32_t *dest, l4_uint32_t val)
565 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
568 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_AND8
570 l4util_and8(volatile l4_uint8_t *dest, l4_uint8_t val)
571 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
574 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_AND16
576 l4util_and16(volatile l4_uint16_t *dest, l4_uint16_t val)
577 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
580 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_AND32
582 l4util_and32(volatile l4_uint32_t *dest, l4_uint32_t val)
583 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
586 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_OR8
588 l4util_or8(volatile l4_uint8_t *dest, l4_uint8_t val)
589 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
592 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_OR16
594 l4util_or16(volatile l4_uint16_t *dest, l4_uint16_t val)
595 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
598 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_OR32
600 l4util_or32(volatile l4_uint32_t *dest, l4_uint32_t val)
601 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); }
604 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_ADD8_RES
606 l4util_add8_res(volatile l4_uint8_t *dest, l4_uint8_t val)
607 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
610 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_ADD16_RES
611 L4_INLINE l4_uint16_t
612 l4util_add16_res(volatile l4_uint16_t *dest, l4_uint16_t val)
613 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
616 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_ADD32_RES
617 L4_INLINE l4_uint32_t
618 l4util_add32_res(volatile l4_uint32_t *dest, l4_uint32_t val)
619 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
622 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_SUB8_RES
624 l4util_sub8_res(volatile l4_uint8_t *dest, l4_uint8_t val)
625 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
628 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_SUB16_RES
629 L4_INLINE l4_uint16_t
630 l4util_sub16_res(volatile l4_uint16_t *dest, l4_uint16_t val)
631 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
634 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_SUB32_RES
635 L4_INLINE l4_uint32_t
636 l4util_sub32_res(volatile l4_uint32_t *dest, l4_uint32_t val)
637 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
640 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_AND8_RES
642 l4util_and8_res(volatile l4_uint8_t *dest, l4_uint8_t val)
643 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
646 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_AND16_RES
647 L4_INLINE l4_uint16_t
648 l4util_and16_res(volatile l4_uint16_t *dest, l4_uint16_t val)
649 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
652 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_AND32_RES
653 L4_INLINE l4_uint32_t
654 l4util_and32_res(volatile l4_uint32_t *dest, l4_uint32_t val)
655 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
658 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_OR8_RES
660 l4util_or8_res(volatile l4_uint8_t *dest, l4_uint8_t val)
661 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
664 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_OR16_RES
665 L4_INLINE l4_uint16_t
666 l4util_or16_res(volatile l4_uint16_t *dest, l4_uint16_t val)
667 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
670 #ifndef __L4UTIL_ATOMIC_HAVE_ARCH_OR32_RES
671 L4_INLINE l4_uint32_t
672 l4util_or32_res(volatile l4_uint32_t *dest, l4_uint32_t val)
673 { (void)dest; (void)val; __this_l4util_atomic_function_is_not_implemented_for_this_arch__sorry(); return 0;}
679 #endif /* ! __L4UTIL__INCLUDE__ATOMIC_H__ */