Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/thread/synch.c
2093 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*
31
* Synchronization primitives.
32
* The specifications of the functions are in synch.h.
33
*/
34
35
#include <types.h>
36
#include <lib.h>
37
#include <spinlock.h>
38
#include <wchan.h>
39
#include <thread.h>
40
#include <current.h>
41
#include <synch.h>
42
43
////////////////////////////////////////////////////////////
44
//
45
// Semaphore.
46
47
struct semaphore *
48
sem_create(const char *name, int initial_count)
49
{
50
struct semaphore *sem;
51
52
KASSERT(initial_count >= 0);
53
54
sem = kmalloc(sizeof(struct semaphore));
55
if (sem == NULL) {
56
return NULL;
57
}
58
59
sem->sem_name = kstrdup(name);
60
if (sem->sem_name == NULL) {
61
kfree(sem);
62
return NULL;
63
}
64
65
sem->sem_wchan = wchan_create(sem->sem_name);
66
if (sem->sem_wchan == NULL) {
67
kfree(sem->sem_name);
68
kfree(sem);
69
return NULL;
70
}
71
72
spinlock_init(&sem->sem_lock);
73
sem->sem_count = initial_count;
74
75
return sem;
76
}
77
78
void
79
sem_destroy(struct semaphore *sem)
80
{
81
KASSERT(sem != NULL);
82
83
/* wchan_cleanup will assert if anyone's waiting on it */
84
spinlock_cleanup(&sem->sem_lock);
85
wchan_destroy(sem->sem_wchan);
86
kfree(sem->sem_name);
87
kfree(sem);
88
}
89
90
void
91
P(struct semaphore *sem)
92
{
93
KASSERT(sem != NULL);
94
95
/*
96
* May not block in an interrupt handler.
97
*
98
* For robustness, always check, even if we can actually
99
* complete the P without blocking.
100
*/
101
KASSERT(curthread->t_in_interrupt == false);
102
103
spinlock_acquire(&sem->sem_lock);
104
while (sem->sem_count == 0) {
105
/*
106
* Bridge to the wchan lock, so if someone else comes
107
* along in V right this instant the wakeup can't go
108
* through on the wchan until we've finished going to
109
* sleep. Note that wchan_sleep unlocks the wchan.
110
*
111
* Note that we don't maintain strict FIFO ordering of
112
* threads going through the semaphore; that is, we
113
* might "get" it on the first try even if other
114
* threads are waiting. Apparently according to some
115
* textbooks semaphores must for some reason have
116
* strict ordering. Too bad. :-)
117
*
118
* Exercise: how would you implement strict FIFO
119
* ordering?
120
*/
121
wchan_lock(sem->sem_wchan);
122
spinlock_release(&sem->sem_lock);
123
wchan_sleep(sem->sem_wchan);
124
125
spinlock_acquire(&sem->sem_lock);
126
}
127
KASSERT(sem->sem_count > 0);
128
sem->sem_count--;
129
spinlock_release(&sem->sem_lock);
130
}
131
132
void
133
V(struct semaphore *sem)
134
{
135
KASSERT(sem != NULL);
136
137
spinlock_acquire(&sem->sem_lock);
138
139
sem->sem_count++;
140
KASSERT(sem->sem_count > 0);
141
wchan_wakeone(sem->sem_wchan);
142
143
spinlock_release(&sem->sem_lock);
144
}
145
146
////////////////////////////////////////////////////////////
147
//
148
// Lock.
149
150
struct lock *
151
lock_create(const char *name)
152
{
153
struct lock *lock;
154
155
lock = kmalloc(sizeof(struct lock));
156
if (lock == NULL) {
157
return NULL;
158
}
159
160
lock->lk_name = kstrdup(name);
161
if (lock->lk_name == NULL) {
162
kfree(lock);
163
return NULL;
164
}
165
166
lock->lk_wchan = wchan_create(lock->lk_name);
167
if (lock->lk_wchan == NULL) {
168
kfree(lock->lk_name);
169
kfree(lock);
170
return NULL;
171
}
172
spinlock_init(&lock->lk_lock);
173
lock->lk_holder = NULL;
174
175
return lock;
176
}
177
178
void
179
lock_destroy(struct lock *lock)
180
{
181
KASSERT(lock != NULL);
182
KASSERT(lock->lk_holder == NULL);
183
184
spinlock_cleanup(&lock->lk_lock);
185
wchan_destroy(lock->lk_wchan);
186
187
kfree(lock->lk_name);
188
kfree(lock);
189
}
190
191
void
192
lock_acquire(struct lock *lock)
193
{
194
KASSERT(lock != NULL);
195
KASSERT(!(lock_do_i_hold(lock)));
196
KASSERT(curthread->t_in_interrupt == false);
197
198
spinlock_acquire(&lock->lk_lock);
199
while (lock->lk_holder != NULL) {
200
wchan_lock(lock->lk_wchan);
201
spinlock_release(&lock->lk_lock);
202
wchan_sleep(lock->lk_wchan);
203
spinlock_acquire(&lock->lk_lock);
204
}
205
206
lock->lk_holder = curthread;
207
spinlock_release(&lock->lk_lock);
208
}
209
210
void
211
lock_release(struct lock *lock)
212
{
213
KASSERT(lock_do_i_hold(lock));
214
215
spinlock_acquire(&lock->lk_lock);
216
lock->lk_holder = NULL;
217
wchan_wakeone(lock->lk_wchan);
218
spinlock_release(&lock->lk_lock);
219
}
220
221
bool
222
lock_do_i_hold(struct lock *lock)
223
{
224
bool ret;
225
KASSERT(lock != NULL);
226
227
spinlock_acquire(&lock->lk_lock);
228
ret = (lock->lk_holder == curthread);
229
spinlock_release(&lock->lk_lock);
230
231
return ret;
232
}
233
234
////////////////////////////////////////////////////////////
235
//
236
// CV
237
238
239
struct cv *
240
cv_create(const char *name)
241
{
242
struct cv *cv;
243
244
cv = kmalloc(sizeof(struct cv));
245
if (cv == NULL) {
246
return NULL;
247
}
248
249
cv->cv_name = kstrdup(name);
250
if (cv->cv_name==NULL) {
251
kfree(cv);
252
return NULL;
253
}
254
255
cv->cv_wchan = wchan_create(cv->cv_name);
256
if (cv->cv_wchan == NULL) {
257
kfree(cv->cv_name);
258
kfree(cv);
259
return NULL;
260
}
261
262
return cv;
263
}
264
265
void
266
cv_destroy(struct cv *cv)
267
{
268
KASSERT(cv != NULL);
269
270
wchan_destroy(cv->cv_wchan);
271
kfree(cv->cv_name);
272
kfree(cv);
273
}
274
275
void
276
cv_wait(struct cv *cv, struct lock *lock)
277
{
278
KASSERT(lock_do_i_hold(lock));
279
280
wchan_lock(cv->cv_wchan);
281
lock_release(lock);
282
wchan_sleep(cv->cv_wchan);
283
lock_acquire(lock);
284
}
285
286
void
287
cv_signal(struct cv *cv, struct lock *lock)
288
{
289
KASSERT(lock_do_i_hold(lock));
290
291
wchan_wakeone(cv->cv_wchan);
292
}
293
294
void
295
cv_broadcast(struct cv *cv, struct lock *lock)
296
{
297
KASSERT(lock_do_i_hold(lock));
298
299
wchan_wakeall(cv->cv_wchan);
300
}
301
302