1.0.27.8: slightly faster x86oid pseudo atomic with {e,r}bp
[sbcl.git] / src / runtime / pseudo-atomic.h
1 /*
2  * macros for manipulating pseudo-atomic flags (per thread)
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15
16 #ifndef PSEUDO_ATOMIC_H
17 #define PSEUDO_ATOMIC_H
18
19 #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
20
21 #define set_alloc_pointer(value)                \
22     SetSymbolValue(ALLOCATION_POINTER, value, 0)
23 #define get_alloc_pointer()                     \
24     SymbolValue(ALLOCATION_POINTER, 0)
25 #define get_binding_stack_pointer(thread)       \
26     SymbolValue(BINDING_STACK_POINTER, thread)
27
28 #if defined(LISP_FEATURE_X86)
29 #define LISPOBJ_ASM_SUFFIX "l"
30 #elif defined(LISP_FEATURE_X86_64)
31 #define LISPOBJ_ASM_SUFFIX "q"
32 #endif
33
34 static inline int
35 get_pseudo_atomic_atomic(struct thread *thread)
36 {
37     return SymbolValue(PSEUDO_ATOMIC_BITS, thread) & (~1);
38 }
39
40 static inline void
41 set_pseudo_atomic_atomic(struct thread *thread)
42 {
43     lispobj *p = SymbolValueAddress(PSEUDO_ATOMIC_BITS, thread);
44     if (*p)
45         lose("set_pseudo_atomic_atomic: pseudo atomic bits is %d.", *p);
46     __asm__ __volatile__
47         ("or" LISPOBJ_ASM_SUFFIX " %0,%1"
48          :
49          : "g" (~1), "m" (*p)
50          : "memory");
51 }
52
53 static inline void
54 clear_pseudo_atomic_atomic(struct thread *thread)
55 {
56     lispobj *p = SymbolValueAddress(PSEUDO_ATOMIC_BITS, thread);
57     __asm__ __volatile__
58         ("and" LISPOBJ_ASM_SUFFIX " %0,%1"
59          :
60          : "g" (1), "m" (*p)
61          : "memory");
62 }
63
64 static inline int
65 get_pseudo_atomic_interrupted(struct thread *thread)
66 {
67     return SymbolValue(PSEUDO_ATOMIC_BITS, thread) & 1;
68 }
69
70 static inline void
71 set_pseudo_atomic_interrupted(struct thread *thread)
72 {
73     if (!get_pseudo_atomic_atomic(thread))
74         lose("set_pseudo_atomic_interrupted not in pseudo atomic");
75     lispobj *p = SymbolValueAddress(PSEUDO_ATOMIC_BITS, thread);
76     __asm__ __volatile__
77         ("or" LISPOBJ_ASM_SUFFIX " %0,%1"
78          :
79          : "g" (1), "m" (*p)
80          : "memory");
81 }
82
83 static inline void
84 clear_pseudo_atomic_interrupted(struct thread *thread)
85 {
86     if (get_pseudo_atomic_atomic(thread))
87         lose("clear_pseudo_atomic_interrupted in pseudo atomic");
88     lispobj *p = SymbolValueAddress(PSEUDO_ATOMIC_BITS, thread);
89     __asm__ __volatile__
90         ("and" LISPOBJ_ASM_SUFFIX " %0,%1"
91          :
92          : "g" (~1), "m" (*p)
93          : "memory");
94 }
95
96 #undef LISPOBJ_SUFFIX
97
98 #elif defined(LISP_FEATURE_PPC) && defined(LISP_FEATURE_GENCGC)
99
100 /* FIXME: Are these async signal safe? Compiler reordering? */
101
102 #define set_alloc_pointer(value) \
103     (dynamic_space_free_pointer = \
104      ((lispobj *) \
105       ((value) | (((unsigned long)dynamic_space_free_pointer) & LOWTAG_MASK))))
106
107 #define get_alloc_pointer()                                     \
108     ((unsigned long) dynamic_space_free_pointer & ~LOWTAG_MASK)
109 #define get_binding_stack_pointer(thread)       \
110     (current_binding_stack_pointer)
111 #define get_pseudo_atomic_atomic(thread)                                \
112     ((unsigned long)dynamic_space_free_pointer & flag_PseudoAtomic)
113 #define set_pseudo_atomic_atomic(thread)                                \
114     (dynamic_space_free_pointer                                         \
115      = (lispobj*) ((unsigned long)dynamic_space_free_pointer | flag_PseudoAtomic))
116 #define clear_pseudo_atomic_atomic(thread)                              \
117     (dynamic_space_free_pointer                                         \
118      = (lispobj*) ((unsigned long) dynamic_space_free_pointer & ~flag_PseudoAtomic))
119 #define get_pseudo_atomic_interrupted(thread)                           \
120     ((unsigned long) dynamic_space_free_pointer & flag_PseudoAtomicInterrupted)
121 #define clear_pseudo_atomic_interrupted(thread)                         \
122     (dynamic_space_free_pointer                                         \
123      = (lispobj*) ((unsigned long) dynamic_space_free_pointer & ~flag_PseudoAtomicInterrupted))
124 #define set_pseudo_atomic_interrupted(thread)                           \
125     (dynamic_space_free_pointer                                         \
126      = (lispobj*) ((unsigned long) dynamic_space_free_pointer | flag_PseudoAtomicInterrupted))
127
128 #endif
129
130 #endif /* PSEUDO_ATOMIC_H */
131