File: /usr/src/linux/include/asm-i386/spinlock.h

1     #ifndef __ASM_SPINLOCK_H
2     #define __ASM_SPINLOCK_H
3     
4     #include <asm/atomic.h>
5     #include <asm/rwlock.h>
6     #include <asm/page.h>
7     #include <linux/config.h>
8     
9     extern int printk(const char * fmt, ...)
10     	__attribute__ ((format (printf, 1, 2)));
11     
12     /* It seems that people are forgetting to
13      * initialize their spinlocks properly, tsk tsk.
14      * Remember to turn this off in 2.4. -ben
15      */
16     #if defined(CONFIG_DEBUG_SPINLOCK)
17     #define SPINLOCK_DEBUG	1
18     #else
19     #define SPINLOCK_DEBUG	0
20     #endif
21     
22     /*
23      * Your basic SMP spinlocks, allowing only a single CPU anywhere
24      */
25     
26     typedef struct {
27     	volatile unsigned int lock;
28     #if SPINLOCK_DEBUG
29     	unsigned magic;
30     #endif
31     } spinlock_t;
32     
33     #define SPINLOCK_MAGIC	0xdead4ead
34     
35     #if SPINLOCK_DEBUG
36     #define SPINLOCK_MAGIC_INIT	, SPINLOCK_MAGIC
37     #else
38     #define SPINLOCK_MAGIC_INIT	/* */
39     #endif
40     
41     #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT }
42     
43     #define spin_lock_init(x)	do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
44     
45     /*
46      * Simple spin lock operations.  There are two variants, one clears IRQ's
47      * on the local processor, one does not.
48      *
49      * We make no fairness assumptions. They have a cost.
50      */
51     
52     #define spin_is_locked(x)	(*(volatile char *)(&(x)->lock) <= 0)
53     #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
54     
55     #define spin_lock_string \
56     	"\n1:\t" \
57     	"lock ; decb %0\n\t" \
58     	"js 2f\n" \
59     	".section .text.lock,\"ax\"\n" \
60     	"2:\t" \
61     	"cmpb $0,%0\n\t" \
62     	"rep;nop\n\t" \
63     	"jle 2b\n\t" \
64     	"jmp 1b\n" \
65     	".previous"
66     
67     /*
68      * This works. Despite all the confusion.
69      */
70     #define spin_unlock_string \
71     	"movb $1,%0"
72     
73     static inline int spin_trylock(spinlock_t *lock)
74     {
75     	char oldval;
76     	__asm__ __volatile__(
77     		"xchgb %b0,%1"
78     		:"=q" (oldval), "=m" (lock->lock)
79     		:"0" (0) : "memory");
80     	return oldval > 0;
81     }
82     
83     static inline void spin_lock(spinlock_t *lock)
84     {
85     #if SPINLOCK_DEBUG
86     	__label__ here;
87     here:
88     	if (lock->magic != SPINLOCK_MAGIC) {
89     printk("eip: %p\n", &&here);
90     		BUG();
91     	}
92     #endif
93     	__asm__ __volatile__(
94     		spin_lock_string
95     		:"=m" (lock->lock) : : "memory");
96     }
97     
98     static inline void spin_unlock(spinlock_t *lock)
99     {
100     #if SPINLOCK_DEBUG
101     	if (lock->magic != SPINLOCK_MAGIC)
102     		BUG();
103     	if (!spin_is_locked(lock))
104     		BUG();
105     #endif
106     	__asm__ __volatile__(
107     		spin_unlock_string
108     		:"=m" (lock->lock) : : "memory");
109     }
110     
111     /*
112      * Read-write spinlocks, allowing multiple readers
113      * but only one writer.
114      *
115      * NOTE! it is quite common to have readers in interrupts
116      * but no interrupt writers. For those circumstances we
117      * can "mix" irq-safe locks - any writer needs to get a
118      * irq-safe write-lock, but readers can get non-irqsafe
119      * read-locks.
120      */
121     typedef struct {
122     	volatile unsigned int lock;
123     #if SPINLOCK_DEBUG
124     	unsigned magic;
125     #endif
126     } rwlock_t;
127     
128     #define RWLOCK_MAGIC	0xdeaf1eed
129     
130     #if SPINLOCK_DEBUG
131     #define RWLOCK_MAGIC_INIT	, RWLOCK_MAGIC
132     #else
133     #define RWLOCK_MAGIC_INIT	/* */
134     #endif
135     
136     #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
137     
138     #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
139     
140     /*
141      * On x86, we implement read-write locks as a 32-bit counter
142      * with the high bit (sign) being the "contended" bit.
143      *
144      * The inline assembly is non-obvious. Think about it.
145      *
146      * Changed to use the same technique as rw semaphores.  See
147      * semaphore.h for details.  -ben
148      */
149     /* the spinlock helpers are in arch/i386/kernel/semaphore.c */
150     
151     static inline void read_lock(rwlock_t *rw)
152     {
153     #if SPINLOCK_DEBUG
154     	if (rw->magic != RWLOCK_MAGIC)
155     		BUG();
156     #endif
157     	__build_read_lock(rw, "__read_lock_failed");
158     }
159     
160     static inline void write_lock(rwlock_t *rw)
161     {
162     #if SPINLOCK_DEBUG
163     	if (rw->magic != RWLOCK_MAGIC)
164     		BUG();
165     #endif
166     	__build_write_lock(rw, "__write_lock_failed");
167     }
168     
169     #define read_unlock(rw)		asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory")
170     #define write_unlock(rw)	asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory")
171     
172     static inline int write_trylock(rwlock_t *lock)
173     {
174     	atomic_t *count = (atomic_t *)lock;
175     	if (atomic_sub_and_test(RW_LOCK_BIAS, count))
176     		return 1;
177     	atomic_add(RW_LOCK_BIAS, count);
178     	return 0;
179     }
180     
181     #endif /* __ASM_SPINLOCK_H */
182