Statistics
| Branch: | Revision:

root / qemu-lock.h @ c227f099

History | View | Annotate | Download (6 kB)

1
/*
2
 *  Copyright (c) 2003 Fabrice Bellard
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2 of the License, or (at your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
16
 */
17

    
18
/* Locking primitives.  Most of this code should be redundant -
19
   system emulation doesn't need/use locking, NPTL userspace uses
20
   pthread mutexes, and non-NPTL userspace isn't threadsafe anyway.
21
   In either case a spinlock is probably the wrong kind of lock.
22
   Spinlocks are only good if you know annother CPU has the lock and is
23
   likely to release it soon.  In environments where you have more threads
24
   than physical CPUs (the extreme case being a single CPU host) a spinlock
25
   simply wastes CPU until the OS decides to preempt it.  */
26
#if defined(CONFIG_USE_NPTL)
27

    
28
#include <pthread.h>
29
#define spin_lock pthread_mutex_lock
30
#define spin_unlock pthread_mutex_unlock
31
#define spinlock_t pthread_mutex_t
32
#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
33

    
34
#else
35

    
36
#if defined(__hppa__)
37

    
38
typedef int spinlock_t[4];
39

    
40
#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 }
41

    
42
static inline void resetlock (spinlock_t *p)
43
{
44
    (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1;
45
}
46

    
47
#else
48

    
49
typedef int spinlock_t;
50

    
51
#define SPIN_LOCK_UNLOCKED 0
52

    
53
static inline void resetlock (spinlock_t *p)
54
{
55
    *p = SPIN_LOCK_UNLOCKED;
56
}
57

    
58
#endif
59

    
60
#if defined(_ARCH_PPC)
61
static inline int testandset (int *p)
62
{
63
    int ret;
64
    __asm__ __volatile__ (
65
                          "      lwarx %0,0,%1\n"
66
                          "      xor. %0,%3,%0\n"
67
                          "      bne $+12\n"
68
                          "      stwcx. %2,0,%1\n"
69
                          "      bne- $-16\n"
70
                          : "=&r" (ret)
71
                          : "r" (p), "r" (1), "r" (0)
72
                          : "cr0", "memory");
73
    return ret;
74
}
75
#elif defined(__i386__)
76
static inline int testandset (int *p)
77
{
78
    long int readval = 0;
79

    
80
    __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
81
                          : "+m" (*p), "+a" (readval)
82
                          : "r" (1)
83
                          : "cc");
84
    return readval;
85
}
86
#elif defined(__x86_64__)
87
static inline int testandset (int *p)
88
{
89
    long int readval = 0;
90

    
91
    __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
92
                          : "+m" (*p), "+a" (readval)
93
                          : "r" (1)
94
                          : "cc");
95
    return readval;
96
}
97
#elif defined(__s390__)
98
static inline int testandset (int *p)
99
{
100
    int ret;
101

    
102
    __asm__ __volatile__ ("0: cs    %0,%1,0(%2)\n"
103
                          "   jl    0b"
104
                          : "=&d" (ret)
105
                          : "r" (1), "a" (p), "0" (*p)
106
                          : "cc", "memory" );
107
    return ret;
108
}
109
#elif defined(__alpha__)
110
static inline int testandset (int *p)
111
{
112
    int ret;
113
    unsigned long one;
114

    
115
    __asm__ __volatile__ ("0:        mov 1,%2\n"
116
                          "        ldl_l %0,%1\n"
117
                          "        stl_c %2,%1\n"
118
                          "        beq %2,1f\n"
119
                          ".subsection 2\n"
120
                          "1:        br 0b\n"
121
                          ".previous"
122
                          : "=r" (ret), "=m" (*p), "=r" (one)
123
                          : "m" (*p));
124
    return ret;
125
}
126
#elif defined(__sparc__)
127
static inline int testandset (int *p)
128
{
129
        int ret;
130

    
131
        __asm__ __volatile__("ldstub        [%1], %0"
132
                             : "=r" (ret)
133
                             : "r" (p)
134
                             : "memory");
135

    
136
        return (ret ? 1 : 0);
137
}
138
#elif defined(__arm__)
139
static inline int testandset (int *spinlock)
140
{
141
    register unsigned int ret;
142
    __asm__ __volatile__("swp %0, %1, [%2]"
143
                         : "=r"(ret)
144
                         : "0"(1), "r"(spinlock));
145

    
146
    return ret;
147
}
148
#elif defined(__mc68000)
149
static inline int testandset (int *p)
150
{
151
    char ret;
152
    __asm__ __volatile__("tas %1; sne %0"
153
                         : "=r" (ret)
154
                         : "m" (p)
155
                         : "cc","memory");
156
    return ret;
157
}
158
#elif defined(__hppa__)
159

    
160
/* Because malloc only guarantees 8-byte alignment for malloc'd data,
161
   and GCC only guarantees 8-byte alignment for stack locals, we can't
162
   be assured of 16-byte alignment for atomic lock data even if we
163
   specify "__attribute ((aligned(16)))" in the type declaration.  So,
164
   we use a struct containing an array of four ints for the atomic lock
165
   type and dynamically select the 16-byte aligned int from the array
166
   for the semaphore.  */
167
#define __PA_LDCW_ALIGNMENT 16
168
static inline void *ldcw_align (void *p) {
169
    unsigned long a = (unsigned long)p;
170
    a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1);
171
    return (void *)a;
172
}
173

    
174
static inline int testandset (spinlock_t *p)
175
{
176
    unsigned int ret;
177
    p = ldcw_align(p);
178
    __asm__ __volatile__("ldcw 0(%1),%0"
179
                         : "=r" (ret)
180
                         : "r" (p)
181
                         : "memory" );
182
    return !ret;
183
}
184

    
185
#elif defined(__ia64)
186

    
187
#include <ia64intrin.h>
188

    
189
static inline int testandset (int *p)
190
{
191
    return __sync_lock_test_and_set (p, 1);
192
}
193
#elif defined(__mips__)
194
static inline int testandset (int *p)
195
{
196
    int ret;
197

    
198
    __asm__ __volatile__ (
199
        "        .set push                \n"
200
        "        .set noat                \n"
201
        "        .set mips2                \n"
202
        "1:        li        $1, 1                \n"
203
        "        ll        %0, %1                \n"
204
        "        sc        $1, %1                \n"
205
        "        beqz        $1, 1b                \n"
206
        "        .set pop                "
207
        : "=r" (ret), "+R" (*p)
208
        :
209
        : "memory");
210

    
211
    return ret;
212
}
213
#else
214
#error unimplemented CPU support
215
#endif
216

    
217
#if defined(CONFIG_USER_ONLY)
218
static inline void spin_lock(spinlock_t *lock)
219
{
220
    while (testandset(lock));
221
}
222

    
223
static inline void spin_unlock(spinlock_t *lock)
224
{
225
    resetlock(lock);
226
}
227

    
228
static inline int spin_trylock(spinlock_t *lock)
229
{
230
    return !testandset(lock);
231
}
232
#else
233
static inline void spin_lock(spinlock_t *lock)
234
{
235
}
236

    
237
static inline void spin_unlock(spinlock_t *lock)
238
{
239
}
240

    
241
static inline int spin_trylock(spinlock_t *lock)
242
{
243
    return 1;
244
}
245
#endif
246

    
247
#endif