Subversion Repositories shark

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
422 giacomo 1
#ifndef _I386_SEMAPHORE_H
2
#define _I386_SEMAPHORE_H
3
 
4
#include <linux/linkage.h>
5
 
6
#ifdef __KERNEL__
7
 
8
/*
9
 * SMP- and interrupt-safe semaphores..
10
 *
11
 * (C) Copyright 1996 Linus Torvalds
12
 *
13
 * Modified 1996-12-23 by Dave Grothe <dave@gcom.com> to fix bugs in
14
 *                     the original code and to make semaphore waits
15
 *                     interruptible so that processes waiting on
16
 *                     semaphores can be killed.
17
 * Modified 1999-02-14 by Andrea Arcangeli, split the sched.c helper
18
 *                     functions in asm/sempahore-helper.h while fixing a
19
 *                     potential and subtle race discovered by Ulrich Schmid
20
 *                     in down_interruptible(). Since I started to play here I
21
 *                     also implemented the `trylock' semaphore operation.
22
 *          1999-07-02 Artur Skawina <skawina@geocities.com>
23
 *                     Optimized "0(ecx)" -> "(ecx)" (the assembler does not
24
 *                     do this). Changed calling sequences from push/jmp to
25
 *                     traditional call/ret.
26
 * Modified 2001-01-01 Andreas Franck <afranck@gmx.de>
27
 *                     Some hacks to ensure compatibility with recent
28
 *                     GCC snapshots, to avoid stack corruption when compiling
29
 *                     with -fomit-frame-pointer. It's not sure if this will
30
 *                     be fixed in GCC, as our previous implementation was a
31
 *                     bit dubious.
32
 *
33
 * If you would like to see an analysis of this implementation, please
34
 * ftp to gcom.com and download the file
35
 * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz.
36
 *
37
 */
38
 
39
#include <asm/system.h>
40
#include <asm/atomic.h>
41
#include <linux/wait.h>
42
#include <linux/rwsem.h>
43
 
44
struct semaphore {
45
        atomic_t count;
46
        int sleepers;
47
        wait_queue_head_t wait;
48
#ifdef WAITQUEUE_DEBUG
49
        long __magic;
50
#endif
51
};
52
 
53
#ifdef WAITQUEUE_DEBUG
54
# define __SEM_DEBUG_INIT(name) \
55
                , (int)&(name).__magic
56
#else
57
# define __SEM_DEBUG_INIT(name)
58
#endif
59
 
60
#define __SEMAPHORE_INITIALIZER(name,count) \
61
{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
62
        __SEM_DEBUG_INIT(name) }
63
 
64
#define __MUTEX_INITIALIZER(name) \
65
        __SEMAPHORE_INITIALIZER(name,1)
66
 
67
#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
68
        struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
69
 
70
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
71
#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
72
 
73
static inline void sema_init (struct semaphore *sem, int val)
74
{
75
/*
76
 *      *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
77
 *
78
 * i'd rather use the more flexible initialization above, but sadly
79
 * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well.
80
 */
81
        atomic_set(&sem->count, val);
82
        sem->sleepers = 0;
83
        init_waitqueue_head(&sem->wait);
84
#ifdef WAITQUEUE_DEBUG
85
        sem->__magic = (int)&sem->__magic;
86
#endif
87
}
88
 
89
static inline void init_MUTEX (struct semaphore *sem)
90
{
91
        sema_init(sem, 1);
92
}
93
 
94
static inline void init_MUTEX_LOCKED (struct semaphore *sem)
95
{
96
        sema_init(sem, 0);
97
}
98
 
99
asmlinkage void __down_failed(void /* special register calling convention */);
100
asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
101
asmlinkage int  __down_failed_trylock(void  /* params in registers */);
102
asmlinkage void __up_wakeup(void /* special register calling convention */);
103
 
104
asmlinkage void __down(struct semaphore * sem);
105
asmlinkage int  __down_interruptible(struct semaphore * sem);
106
asmlinkage int  __down_trylock(struct semaphore * sem);
107
asmlinkage void __up(struct semaphore * sem);
108
 
109
/*
110
 * This is ugly, but we want the default case to fall through.
111
 * "__down_failed" is a special asm handler that calls the C
112
 * routine that actually waits. See arch/i386/kernel/semaphore.c
113
 */
114
static inline void down(struct semaphore * sem)
115
{
116
#ifdef WAITQUEUE_DEBUG
117
        CHECK_MAGIC(sem->__magic);
118
#endif
119
        might_sleep();
120
        __asm__ __volatile__(
121
                "# atomic down operation\n\t"
122
                LOCK "decl %0\n\t"     /* --sem->count */
123
                "js 2f\n"
124
                "1:\n"
125
                LOCK_SECTION_START("")
126
                "2:\tcall __down_failed\n\t"
127
                "jmp 1b\n"
128
                LOCK_SECTION_END
129
                :"=m" (sem->count)
130
                :"c" (sem)
131
                :"memory");
132
}
133
 
134
/*
135
 * Interruptible try to acquire a semaphore.  If we obtained
136
 * it, return zero.  If we were interrupted, returns -EINTR
137
 */
138
static inline int down_interruptible(struct semaphore * sem)
139
{
140
        int result;
141
 
142
#ifdef WAITQUEUE_DEBUG
143
        CHECK_MAGIC(sem->__magic);
144
#endif
145
        might_sleep();
146
        __asm__ __volatile__(
147
                "# atomic interruptible down operation\n\t"
148
                LOCK "decl %1\n\t"     /* --sem->count */
149
                "js 2f\n\t"
150
                "xorl %0,%0\n"
151
                "1:\n"
152
                LOCK_SECTION_START("")
153
                "2:\tcall __down_failed_interruptible\n\t"
154
                "jmp 1b\n"
155
                LOCK_SECTION_END
156
                :"=a" (result), "=m" (sem->count)
157
                :"c" (sem)
158
                :"memory");
159
        return result;
160
}
161
 
162
/*
163
 * Non-blockingly attempt to down() a semaphore.
164
 * Returns zero if we acquired it
165
 */
166
static inline int down_trylock(struct semaphore * sem)
167
{
168
        int result;
169
 
170
#ifdef WAITQUEUE_DEBUG
171
        CHECK_MAGIC(sem->__magic);
172
#endif
173
 
174
        __asm__ __volatile__(
175
                "# atomic interruptible down operation\n\t"
176
                LOCK "decl %1\n\t"     /* --sem->count */
177
                "js 2f\n\t"
178
                "xorl %0,%0\n"
179
                "1:\n"
180
                LOCK_SECTION_START("")
181
                "2:\tcall __down_failed_trylock\n\t"
182
                "jmp 1b\n"
183
                LOCK_SECTION_END
184
                :"=a" (result), "=m" (sem->count)
185
                :"c" (sem)
186
                :"memory");
187
        return result;
188
}
189
 
190
/*
191
 * Note! This is subtle. We jump to wake people up only if
192
 * the semaphore was negative (== somebody was waiting on it).
193
 * The default case (no contention) will result in NO
194
 * jumps for both down() and up().
195
 */
196
static inline void up(struct semaphore * sem)
197
{
198
#ifdef WAITQUEUE_DEBUG
199
        CHECK_MAGIC(sem->__magic);
200
#endif
201
        __asm__ __volatile__(
202
                "# atomic up operation\n\t"
203
                LOCK "incl %0\n\t"     /* ++sem->count */
204
                "jle 2f\n"
205
                "1:\n"
206
                LOCK_SECTION_START("")
207
                "2:\tcall __up_wakeup\n\t"
208
                "jmp 1b\n"
209
                LOCK_SECTION_END
210
                ".subsection 0\n"
211
                :"=m" (sem->count)
212
                :"c" (sem)
213
                :"memory");
214
}
215
 
216
#endif
217
#endif