ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/libpeak-0.1.2/peak/arch/powerpc/spinlock.h
Revision: 3251
Committed: Wed Apr 2 16:58:30 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-chdr
File size: 5188 byte(s)
Log Message:
- Imported libpeak-0.1.2

File Contents

# Content
1 /*
2 * PowerPC spinlock operations.
3 * With the help of various source: Darwin, Linux kernel...
4 *
5 * $Id: spinlock.h.in,v 1.1 2007/05/24 12:54:10 mbuna Exp $
6 */
7 #ifndef INCLUDED_PEAK_SPINLOCK_H_
8 #define INCLUDED_PEAK_SPINLOCK_H_
9
10 #define PEAK_SPINLOCK_ITERATIONS 1000
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15 #include <sys/types.h>
16 #include <sys/time.h>
17 #include <sys/signal.h>
18 #include <pthread.h>
19 #include <unistd.h>
20 #ifdef HAVE_SCHED_H
21 #include <sched.h>
22 #endif
23 #ifdef HAVE_ATOMIC_OP_H
24 #include <sys/atomic_op.h> /* AIX */
25 #endif
26
27 #include <peak/stdint.h>
28
29 /* Erratum #77 on the 405 means we need a sync or dcbt before every stwcx.
30 * The old ATOMIC_SYNC_FIX covered some but not all of this.
31 */
32 #ifdef CONFIG_IBM405_ERR77
33 #define PPC405_ERR77(ra,rb) "dcbt " #ra "," #rb ";"
34 #else
35 #define PPC405_ERR77(ra,rb)
36 #endif
37
38 /* PEAK defaults to SMP
39 */
40 #ifdef PEAK_CONFIG_UNIPROCESSOR
41 #define SMP_WMB
42 #define SMP_MB
43 #else
44 #define SMP_WMB "eieio\n"
45 #define SMP_MB "\nsync"
46 #endif /* PEAK_CONFIG_UNIPROCESSOR */
47
48
49 #if defined(__cplusplus)
50 extern "C" {
51 #endif
52
53 /* PEAK INTERNAL SPIN LOCK
54 *
55 * _peak_spinlock_lock(lockp)
56 * _peak_spinlock_lock_try(lockp) - returns 0 (busy) or 1 (got the lock)
57 * _peak_spinlock_unlock(lockp)
58 *
59 */
60
61 extern int _peak_is_threaded;
62
63 #if defined(HAVE__SPIN_LOCK) && defined(HAVE__SPIN_LOCK_TRY) && defined(HAVE__SPIN_UNLOCK)
64 #define USE_DARWIN_SPINLOCK 1
65 #else
66 #define USE_DARWIN_SPINLOCK 0
67 #endif
68
69 /* Type and initializer for this architecture.
70 */
71 #if USE_DARWIN_SPINLOCK
72 typedef volatile long peak_spinlock_t;
73 #define PEAK_SPINLOCK_INITIALIZER (0)
74 #elif defined(__GNUC__)
75 typedef struct { volatile unsigned long lock; } peak_spinlock_t;
76 #define PEAK_SPINLOCK_INITIALIZER ((peak_spinlock_t){ (0) })
77 #elif defined(_AIX)
78 typedef int peak_spinlock_t; /* AIX: typedef int *atomic_p; */
79 #define PEAK_SPINLOCK_INITIALIZER (0)
80 #endif
81
82 #if USE_DARWIN_SPINLOCK
83 extern void _spin_lock(peak_spinlock_t *lockp);
84 extern int _spin_lock_try(peak_spinlock_t *lockp);
85 extern void _spin_unlock(peak_spinlock_t *lockp);
86 #endif
87
88 static inline void
89 _peak_spinlock_lock(peak_spinlock_t *lockp)
90 {
91 #if USE_DARWIN_SPINLOCK
92
93 if (!_peak_is_threaded) /* set only if peak uses several threads */
94 return;
95
96 _spin_lock(lockp); /* Lucky, we have a system function for that.
97 * I checked on Darwin 7.0 and it deals properly
98 * with 32 or 64 bit, UP (always depress) or
99 * MP (1000 spin tries before relinquish).
100 * On Darwin 6.x, however, the kernel use generic
101 * PPC MP code, but well. --mbuna
102 */
103
104 #elif defined(__GNUC__)
105
106 unsigned long tmp;
107
108 if (!_peak_is_threaded) /* set only if peak uses several threads */
109 return;
110
111 __asm__ __volatile__(
112 "b 1f # spin_lock\n\
113 2: lwzx %0,0,%1\n\
114 cmpwi 0,%0,0\n\
115 bne+ 2b\n\
116 1: lwarx %0,0,%1\n\
117 cmpwi 0,%0,0\n\
118 bne- 2b\n"
119 PPC405_ERR77(0,%1)
120 " stwcx. %2,0,%1\n\
121 bne- 2b\n\
122 isync"
123 : "=&r"(tmp)
124 : "r"(&lockp->lock), "r"(1)
125 : "cr0", "memory");
126
127 #elif defined(_AIX)
128
129 unsigned int tries = PEAK_SPINLOCK_ITERATIONS;
130
131 if (!_peak_is_threaded) /* set only if peak uses several threads */
132 return;
133
134 while (!_check_lock(lockp, 0, 1))
135 {
136 if (--tries > 0)
137 {
138 sched_yield();
139 tries = PEAK_SPINLOCK_ITERATIONS;
140 }
141 }
142
143 #else
144 #error _peak_spinlock_lock not supported
145 #endif /* USE_DARWIN_SPINLOCK */
146 }
147
148 static inline int
149 _peak_spinlock_lock_try(peak_spinlock_t *lockp)
150 {
151 #if USE_DARWIN_SPINLOCK
152 if (!_peak_is_threaded) /* set only if peak uses several threads */
153 return 1; /* always succeed */
154
155 return _spin_lock_try(lockp);
156 #elif defined(__GNUC__)
157 unsigned int old, t;
158 unsigned int mask = 1;
159 volatile unsigned int *p = ((volatile unsigned int *)lockp->lock);
160
161 if (!_peak_is_threaded) /* set only if peak uses several threads */
162 return 1; /* always succeed */
163
164 __asm__ __volatile__(SMP_WMB "\n\
165 1: lwarx %0,0,%4 \n\
166 or %1,%0,%3 \n"
167 PPC405_ERR77(0,%4)
168 " stwcx. %1,0,%4 \n\
169 bne 1b"
170 SMP_MB
171 : "=&r" (old), "=&r" (t), "=m" (*p)
172 : "r" (mask), "r" (p), "m" (*p)
173 : "cc", "memory");
174
175 return (old & mask) == 0;
176 #elif defined(_AIX)
177 return !_check_lock(lockp, 0, 1);
178 #else
179 #error _peak_spinlock_lock_try not supported
180 #endif
181 }
182
183 static inline void
184 _peak_spinlock_unlock(peak_spinlock_t *lockp)
185 {
186 if (!_peak_is_threaded) /* set only if peak uses several threads */
187 return;
188
189 #if USE_DARWIN_SPINLOCK
190 if (!_peak_is_threaded) /* set only if peak uses several threads */
191 return;
192
193 _spin_unlock(lockp);
194
195 #elif defined(__GNUC__)
196 /* The eieio instruction is a faster sync: a barrier providing an ordering
197 * (separately) for (a) cacheable stores and (b) loads and stores to
198 * non-cacheable memory (e.g. I/O devices).
199 */
200 __asm__ __volatile__("eieio # spin_unlock": : :"memory");
201 lockp->lock = 0;
202 #elif defined(_AIX)
203 _clear_lock(lockp, 0);
204 #else
205 #error _peak_spinlock_unlock not supported
206 #endif
207 }
208
209 #if defined(__cplusplus)
210 }
211 #endif
212
213 #endif /* INCLUDED_PEAK_SPINLOCK_H_ */