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

# User Rev Content
1 michael 3251 /*
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_ */