%other-pointer-widetag derive-type: derive for simple-array.
[sbcl.git] / src / runtime / pseudo-atomic.h
blobb0aa7a9af4c8c8d054056800b50984c03a61dd1e
1 /*
2 * macros for getting/setting the pseudo-atomic flags (per thread, if applicable)
3 */
5 /*
6 * This software is part of the SBCL system. See the README file for
7 * more information.
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.
16 #ifndef PSEUDO_ATOMIC_H
17 #define PSEUDO_ATOMIC_H
19 #include "genesis/thread.h"
20 #include "genesis/static-symbols.h"
21 #include "genesis/symbol.h"
23 #if defined LISP_FEATURE_SPARC || defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64
25 /* These architectures make no distinction between +/- sb-thread.
26 * They always use per-thread bit and never static symbols for the PA bits.
27 * The PA-Atomic field is at byte 0 of the thread slot regardless of endianness.
28 * The PA-Interrupted field is at byte 2 regardless of endian-ness.
29 * This holds for either word size.
30 * These values can be anything - they just have to be compatible between C and Lisp.
31 * Lisp uses NULL-TN to set pseudo-atomic and THREAD-TN to clear it. */
32 # define get_pseudo_atomic_atomic(th) (th)->pseudo_atomic_bits[0] != 0
33 # define set_pseudo_atomic_atomic(th) (th)->pseudo_atomic_bits[0] = 1
34 # define clear_pseudo_atomic_atomic(th) (th)->pseudo_atomic_bits[0] = 0
35 // A 2-byte field allows for 'lhz' followed by 'twi'
36 # define get_pseudo_atomic_interrupted(th) (th)->pseudo_atomic_bits[2] != 0
37 // make it look like a fixnum in case we only have a descriptor register
38 // at our disposal when loading the flag
39 # define set_pseudo_atomic_interrupted(th) (th)->pseudo_atomic_bits[2] = 8
40 # define clear_pseudo_atomic_interrupted(th) (th)->pseudo_atomic_bits[2] = 0
42 #elif defined LISP_FEATURE_ARM || defined LISP_FEATURE_ARM64 \
43 || defined LISP_FEATURE_MIPS || defined LISP_FEATURE_RISCV
44 #include "thread.h" // for SymbolValue
46 /* These architectures use a thread slot if #+sb-thread,
47 * or else two static symbols if #-sb-thread.
48 * The complication is that if using a thread slot, the the values
49 * are stored in two bits, but otherwise the value is the entire word. */
51 #ifdef LISP_FEATURE_SB_THREAD
53 #define get_pseudo_atomic_atomic(thread) \
54 ((thread)->pseudo_atomic_bits & flag_PseudoAtomic)
55 #define set_pseudo_atomic_atomic(thread) \
56 ((thread)->pseudo_atomic_bits |= flag_PseudoAtomic)
57 #define clear_pseudo_atomic_atomic(thread) \
58 ((thread)->pseudo_atomic_bits &= ~flag_PseudoAtomic)
59 #define get_pseudo_atomic_interrupted(thread) \
60 ((thread)->pseudo_atomic_bits & flag_PseudoAtomicInterrupted)
61 #define set_pseudo_atomic_interrupted(thread) \
62 ((thread)->pseudo_atomic_bits |= flag_PseudoAtomicInterrupted)
63 #define clear_pseudo_atomic_interrupted(thread) \
64 ((thread)->pseudo_atomic_bits &= ~flag_PseudoAtomicInterrupted)
66 #else
68 static inline int
69 get_pseudo_atomic_atomic(struct thread *thread)
71 return SymbolValue(PSEUDO_ATOMIC_ATOMIC, thread) != NIL;
74 static inline void
75 set_pseudo_atomic_atomic(struct thread *thread)
77 SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, PSEUDO_ATOMIC_ATOMIC, thread);
80 static inline void
81 clear_pseudo_atomic_atomic(struct thread *thread)
83 SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, NIL, thread);
86 static inline int
87 get_pseudo_atomic_interrupted(struct thread *thread)
89 return SymbolValue(PSEUDO_ATOMIC_INTERRUPTED, thread) != 0;
92 static inline void
93 set_pseudo_atomic_interrupted(struct thread *thread)
95 #ifndef DO_PENDING_INTERRUPT
96 // RISCV defines do_pending_interrupt as a lisp asm routine the address of which
97 // is stored in a static lisp symbol and which in C is obtained via #define.
98 extern void do_pending_interrupt();
99 #endif
100 SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, (lispobj)do_pending_interrupt, thread);
103 static inline void
104 clear_pseudo_atomic_interrupted(struct thread *thread)
106 SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, 0, 0);
108 #endif // LISP_FEATURE_SB_THREAD
110 #elif defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64
112 /* x86 uses either a thread slot, or a single static symbol holding
113 * the same value as the thread slot would hold.
114 * The encoding of the values is strange - the entire word is onzero
115 * whend pseudo-atomic, and the lowest bit should be 0.
116 * If interrupted, the low bit becomes 1. This seems a little bogus because
117 * symbol->value at that point can have "illegal" bits (non-descriptor).
118 * I guess the reason it's allowed is GC can't ever see the bad value.
119 * But it sure seems like it's asking for trouble */
121 #ifdef LISP_FEATURE_X86_64
122 # define LISPOBJ_ASM_SUFFIX "q"
123 #else
124 # define LISPOBJ_ASM_SUFFIX "l"
125 #endif
127 #ifdef LISP_FEATURE_SB_THREAD
128 # define pa_bits thread->pseudo_atomic_bits
129 #else
130 # define pa_bits SYMBOL(PSEUDO_ATOMIC_BITS)->value
131 #endif
133 #include "interr.h" // for lose()
135 static inline int
136 get_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread)
138 // mask out the 'interrupted' bit before testing
139 return (pa_bits & ~1) != 0;
142 // FIXME: all this seems unnecessary use of inline assembly
144 static inline void
145 set_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread)
147 if (pa_bits) lose("set_pseudo_atomic_atomic: bits=%"OBJ_FMTX, pa_bits);
148 __asm__ volatile ("or" LISPOBJ_ASM_SUFFIX " $~1, %0" : "+m" (pa_bits));
151 static inline void
152 clear_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread)
154 __asm__ volatile ("and" LISPOBJ_ASM_SUFFIX " $1, %0" : "+m" (pa_bits));
157 static inline int
158 get_pseudo_atomic_interrupted(struct thread __attribute__((unused)) *thread)
160 return pa_bits & 1;
163 static inline void
164 set_pseudo_atomic_interrupted(struct thread *thread)
166 if (!get_pseudo_atomic_atomic(thread))
167 lose("set_pseudo_atomic_interrupted not in pseudo atomic");
168 __asm__ volatile ("or" LISPOBJ_ASM_SUFFIX " $1, %0" : "+m" (pa_bits));
171 static inline void
172 clear_pseudo_atomic_interrupted(struct thread *thread)
174 if (get_pseudo_atomic_atomic(thread))
175 lose("clear_pseudo_atomic_interrupted in pseudo atomic");
176 __asm__ volatile ("and" LISPOBJ_ASM_SUFFIX " $~1, %0" : "+m" (pa_bits));
178 #undef pa_bits
179 #undef LISPOBJ_ASM_SUFFIX
181 #else
183 #error "architecture needs definition of pseudo-atomic bits"
185 #endif
187 #endif /* PSEUDO_ATOMIC_H */