]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* semaphore.c: FR-V semaphores |
2 | * | |
3 | * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells (dhowells@redhat.com) | |
5 | * - Derived from lib/rwsem-spinlock.c | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License | |
9 | * as published by the Free Software Foundation; either version | |
10 | * 2 of the License, or (at your option) any later version. | |
11 | */ | |
12 | ||
1da177e4 LT |
13 | #include <linux/sched.h> |
14 | #include <linux/module.h> | |
15 | #include <asm/semaphore.h> | |
16 | ||
17 | struct sem_waiter { | |
18 | struct list_head list; | |
19 | struct task_struct *task; | |
20 | }; | |
21 | ||
8080f231 | 22 | #if SEMAPHORE_DEBUG |
1da177e4 LT |
23 | void semtrace(struct semaphore *sem, const char *str) |
24 | { | |
25 | if (sem->debug) | |
26 | printk("[%d] %s({%d,%d})\n", | |
27 | current->pid, | |
28 | str, | |
29 | sem->counter, | |
30 | list_empty(&sem->wait_list) ? 0 : 1); | |
31 | } | |
32 | #else | |
33 | #define semtrace(SEM,STR) do { } while(0) | |
34 | #endif | |
35 | ||
36 | /* | |
37 | * wait for a token to be granted from a semaphore | |
38 | * - entered with lock held and interrupts disabled | |
39 | */ | |
40 | void __down(struct semaphore *sem, unsigned long flags) | |
41 | { | |
42 | struct task_struct *tsk = current; | |
43 | struct sem_waiter waiter; | |
44 | ||
45 | semtrace(sem, "Entering __down"); | |
46 | ||
47 | /* set up my own style of waitqueue */ | |
48 | waiter.task = tsk; | |
49 | get_task_struct(tsk); | |
50 | ||
51 | list_add_tail(&waiter.list, &sem->wait_list); | |
52 | ||
53 | /* we don't need to touch the semaphore struct anymore */ | |
54 | spin_unlock_irqrestore(&sem->wait_lock, flags); | |
55 | ||
56 | /* wait to be given the semaphore */ | |
57 | set_task_state(tsk, TASK_UNINTERRUPTIBLE); | |
58 | ||
59 | for (;;) { | |
60 | if (list_empty(&waiter.list)) | |
61 | break; | |
62 | schedule(); | |
63 | set_task_state(tsk, TASK_UNINTERRUPTIBLE); | |
64 | } | |
65 | ||
66 | tsk->state = TASK_RUNNING; | |
67 | semtrace(sem, "Leaving __down"); | |
68 | } | |
69 | ||
70 | EXPORT_SYMBOL(__down); | |
71 | ||
72 | /* | |
73 | * interruptibly wait for a token to be granted from a semaphore | |
74 | * - entered with lock held and interrupts disabled | |
75 | */ | |
76 | int __down_interruptible(struct semaphore *sem, unsigned long flags) | |
77 | { | |
78 | struct task_struct *tsk = current; | |
79 | struct sem_waiter waiter; | |
80 | int ret; | |
81 | ||
82 | semtrace(sem,"Entering __down_interruptible"); | |
83 | ||
84 | /* set up my own style of waitqueue */ | |
85 | waiter.task = tsk; | |
86 | get_task_struct(tsk); | |
87 | ||
88 | list_add_tail(&waiter.list, &sem->wait_list); | |
89 | ||
90 | /* we don't need to touch the semaphore struct anymore */ | |
91 | set_task_state(tsk, TASK_INTERRUPTIBLE); | |
92 | ||
93 | spin_unlock_irqrestore(&sem->wait_lock, flags); | |
94 | ||
95 | /* wait to be given the semaphore */ | |
96 | ret = 0; | |
97 | for (;;) { | |
98 | if (list_empty(&waiter.list)) | |
99 | break; | |
100 | if (unlikely(signal_pending(current))) | |
101 | goto interrupted; | |
102 | schedule(); | |
103 | set_task_state(tsk, TASK_INTERRUPTIBLE); | |
104 | } | |
105 | ||
106 | out: | |
107 | tsk->state = TASK_RUNNING; | |
108 | semtrace(sem, "Leaving __down_interruptible"); | |
109 | return ret; | |
110 | ||
111 | interrupted: | |
112 | spin_lock_irqsave(&sem->wait_lock, flags); | |
113 | ||
114 | if (!list_empty(&waiter.list)) { | |
115 | list_del(&waiter.list); | |
116 | ret = -EINTR; | |
117 | } | |
118 | ||
119 | spin_unlock_irqrestore(&sem->wait_lock, flags); | |
120 | if (ret == -EINTR) | |
121 | put_task_struct(current); | |
122 | goto out; | |
123 | } | |
124 | ||
125 | EXPORT_SYMBOL(__down_interruptible); | |
126 | ||
127 | /* | |
128 | * release a single token back to a semaphore | |
129 | * - entered with lock held and interrupts disabled | |
130 | */ | |
131 | void __up(struct semaphore *sem) | |
132 | { | |
133 | struct task_struct *tsk; | |
134 | struct sem_waiter *waiter; | |
135 | ||
136 | semtrace(sem,"Entering __up"); | |
137 | ||
138 | /* grant the token to the process at the front of the queue */ | |
139 | waiter = list_entry(sem->wait_list.next, struct sem_waiter, list); | |
140 | ||
141 | /* We must be careful not to touch 'waiter' after we set ->task = NULL. | |
142 | * It is an allocated on the waiter's stack and may become invalid at | |
143 | * any time after that point (due to a wakeup from another source). | |
144 | */ | |
145 | list_del_init(&waiter->list); | |
146 | tsk = waiter->task; | |
147 | mb(); | |
148 | waiter->task = NULL; | |
149 | wake_up_process(tsk); | |
150 | put_task_struct(tsk); | |
151 | ||
152 | semtrace(sem,"Leaving __up"); | |
153 | } | |
154 | ||
155 | EXPORT_SYMBOL(__up); |