OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [LINUX_2_4_26_OR32/] [linux/] [linux-2.4/] [lib/] [rwsem-spinlock.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* rwsem-spinlock.c: R/W semaphores: contention handling functions for generic spinlock
2
 *                                   implementation
3
 *
4
 * Copyright (c) 2001   David Howells (dhowells@redhat.com).
5
 * - Derived partially from idea by Andrea Arcangeli <andrea@suse.de>
6
 * - Derived also from comments by Linus
7
 *
8
 * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
9
 */
10
#include <linux/rwsem.h>
11
#include <linux/sched.h>
12
#include <linux/module.h>
13
 
14
struct rwsem_waiter {
15
        struct list_head        list;
16
        struct task_struct      *task;
17
        unsigned int            flags;
18
#define RWSEM_WAITING_FOR_READ  0x00000001
19
#define RWSEM_WAITING_FOR_WRITE 0x00000002
20
};
21
 
22
#if RWSEM_DEBUG
23
void rwsemtrace(struct rw_semaphore *sem, const char *str)
24
{
25
        if (sem->debug)
26
                printk("[%d] %s({%d,%d})\n",
27
                       current->pid,str,sem->activity,list_empty(&sem->wait_list)?0:1);
28
}
29
#endif
30
 
31
/*
32
 * initialise the semaphore
33
 */
34
void init_rwsem(struct rw_semaphore *sem)
35
{
36
        sem->activity = 0;
37
        spin_lock_init(&sem->wait_lock);
38
        INIT_LIST_HEAD(&sem->wait_list);
39
#if RWSEM_DEBUG
40
        sem->debug = 0;
41
#endif
42
}
43
 
44
/*
45
 * handle the lock being released whilst there are processes blocked on it that can now run
46
 * - if we come here, then:
47
 *   - the 'active count' _reached_ zero
48
 *   - the 'waiting count' is non-zero
49
 * - the spinlock must be held by the caller
50
 * - woken process blocks are discarded from the list after having flags zeroised
51
 */
52
static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem)
53
{
54
        struct rwsem_waiter *waiter;
55
        int woken;
56
 
57
        rwsemtrace(sem,"Entering __rwsem_do_wake");
58
 
59
        waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
60
 
61
        /* try to grant a single write lock if there's a writer at the front of the queue
62
         * - we leave the 'waiting count' incremented to signify potential contention
63
         */
64
        if (waiter->flags & RWSEM_WAITING_FOR_WRITE) {
65
                sem->activity = -1;
66
                list_del(&waiter->list);
67
                waiter->flags = 0;
68
                wake_up_process(waiter->task);
69
                goto out;
70
        }
71
 
72
        /* grant an infinite number of read locks to the readers at the front of the queue */
73
        woken = 0;
74
        do {
75
                list_del(&waiter->list);
76
                waiter->flags = 0;
77
                wake_up_process(waiter->task);
78
                woken++;
79
                if (list_empty(&sem->wait_list))
80
                        break;
81
                waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
82
        } while (waiter->flags&RWSEM_WAITING_FOR_READ);
83
 
84
        sem->activity += woken;
85
 
86
 out:
87
        rwsemtrace(sem,"Leaving __rwsem_do_wake");
88
        return sem;
89
}
90
 
91
/*
92
 * wake a single writer
93
 */
94
static inline struct rw_semaphore *__rwsem_wake_one_writer(struct rw_semaphore *sem)
95
{
96
        struct rwsem_waiter *waiter;
97
 
98
        sem->activity = -1;
99
 
100
        waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
101
        list_del(&waiter->list);
102
 
103
        waiter->flags = 0;
104
        wake_up_process(waiter->task);
105
        return sem;
106
}
107
 
108
/*
109
 * get a read lock on the semaphore
110
 */
111
void __down_read(struct rw_semaphore *sem)
112
{
113
        struct rwsem_waiter waiter;
114
        struct task_struct *tsk;
115
 
116
        rwsemtrace(sem,"Entering __down_read");
117
 
118
        spin_lock(&sem->wait_lock);
119
 
120
        if (sem->activity>=0 && list_empty(&sem->wait_list)) {
121
                /* granted */
122
                sem->activity++;
123
                spin_unlock(&sem->wait_lock);
124
                goto out;
125
        }
126
 
127
        tsk = current;
128
        set_task_state(tsk,TASK_UNINTERRUPTIBLE);
129
 
130
        /* set up my own style of waitqueue */
131
        waiter.task = tsk;
132
        waiter.flags = RWSEM_WAITING_FOR_READ;
133
 
134
        list_add_tail(&waiter.list,&sem->wait_list);
135
 
136
        /* we don't need to touch the semaphore struct anymore */
137
        spin_unlock(&sem->wait_lock);
138
 
139
        /* wait to be given the lock */
140
        for (;;) {
141
                if (!waiter.flags)
142
                        break;
143
                schedule();
144
                set_task_state(tsk, TASK_UNINTERRUPTIBLE);
145
        }
146
 
147
        tsk->state = TASK_RUNNING;
148
 
149
 out:
150
        rwsemtrace(sem,"Leaving __down_read");
151
}
152
 
153
/*
154
 * trylock for reading -- returns 1 if successful, 0 if contention
155
 */
156
int __down_read_trylock(struct rw_semaphore *sem)
157
{
158
        int ret = 0;
159
        rwsemtrace(sem,"Entering __down_read_trylock");
160
 
161
        spin_lock(&sem->wait_lock);
162
 
163
        if (sem->activity>=0 && list_empty(&sem->wait_list)) {
164
                /* granted */
165
                sem->activity++;
166
                ret = 1;
167
        }
168
 
169
        spin_unlock(&sem->wait_lock);
170
 
171
        rwsemtrace(sem,"Leaving __down_read_trylock");
172
        return ret;
173
}
174
 
175
/*
176
 * get a write lock on the semaphore
177
 * - note that we increment the waiting count anyway to indicate an exclusive lock
178
 */
179
void __down_write(struct rw_semaphore *sem)
180
{
181
        struct rwsem_waiter waiter;
182
        struct task_struct *tsk;
183
 
184
        rwsemtrace(sem,"Entering __down_write");
185
 
186
        spin_lock(&sem->wait_lock);
187
 
188
        if (sem->activity==0 && list_empty(&sem->wait_list)) {
189
                /* granted */
190
                sem->activity = -1;
191
                spin_unlock(&sem->wait_lock);
192
                goto out;
193
        }
194
 
195
        tsk = current;
196
        set_task_state(tsk,TASK_UNINTERRUPTIBLE);
197
 
198
        /* set up my own style of waitqueue */
199
        waiter.task = tsk;
200
        waiter.flags = RWSEM_WAITING_FOR_WRITE;
201
 
202
        list_add_tail(&waiter.list,&sem->wait_list);
203
 
204
        /* we don't need to touch the semaphore struct anymore */
205
        spin_unlock(&sem->wait_lock);
206
 
207
        /* wait to be given the lock */
208
        for (;;) {
209
                if (!waiter.flags)
210
                        break;
211
                schedule();
212
                set_task_state(tsk, TASK_UNINTERRUPTIBLE);
213
        }
214
 
215
        tsk->state = TASK_RUNNING;
216
 
217
 out:
218
        rwsemtrace(sem,"Leaving __down_write");
219
}
220
 
221
/*
222
 * trylock for writing -- returns 1 if successful, 0 if contention
223
 */
224
int __down_write_trylock(struct rw_semaphore *sem)
225
{
226
        int ret = 0;
227
        rwsemtrace(sem,"Entering __down_write_trylock");
228
 
229
        spin_lock(&sem->wait_lock);
230
 
231
        if (sem->activity==0 && list_empty(&sem->wait_list)) {
232
                /* granted */
233
                sem->activity = -1;
234
                ret = 1;
235
        }
236
 
237
        spin_unlock(&sem->wait_lock);
238
 
239
        rwsemtrace(sem,"Leaving __down_write_trylock");
240
        return ret;
241
}
242
 
243
/*
244
 * release a read lock on the semaphore
245
 */
246
void __up_read(struct rw_semaphore *sem)
247
{
248
        rwsemtrace(sem,"Entering __up_read");
249
 
250
        spin_lock(&sem->wait_lock);
251
 
252
        if (--sem->activity==0 && !list_empty(&sem->wait_list))
253
                sem = __rwsem_wake_one_writer(sem);
254
 
255
        spin_unlock(&sem->wait_lock);
256
 
257
        rwsemtrace(sem,"Leaving __up_read");
258
}
259
 
260
/*
261
 * release a write lock on the semaphore
262
 */
263
void __up_write(struct rw_semaphore *sem)
264
{
265
        rwsemtrace(sem,"Entering __up_write");
266
 
267
        spin_lock(&sem->wait_lock);
268
 
269
        sem->activity = 0;
270
        if (!list_empty(&sem->wait_list))
271
                sem = __rwsem_do_wake(sem);
272
 
273
        spin_unlock(&sem->wait_lock);
274
 
275
        rwsemtrace(sem,"Leaving __up_write");
276
}
277
 
278
EXPORT_SYMBOL(init_rwsem);
279
EXPORT_SYMBOL(__down_read);
280
EXPORT_SYMBOL(__down_write);
281
EXPORT_SYMBOL(__up_read);
282
EXPORT_SYMBOL(__up_write);
283
#if RWSEM_DEBUG
284
EXPORT_SYMBOL(rwsemtrace);
285
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.