blob: 4535d9b372458c01d5f3494040e3cae793567120 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
/**
* @file rwlock.c
* @author Hanjie Wu (hanjiew)
* @author Devang Acharya (devanga)
* @brief RW Lock implementation
* @date 2023-02-22
*
*/
#include <assert.h>
#include <rwlock.h>
/**
* @brief initialize the lock pointed to by rwlock
*
* @param rwlock
* @return int
*/
int rwlock_init(rwlock_t* rwlock) {
rwlock->status = RWLOCK_STATUS_UNLOCK;
rwlock->num_reader = 0;
mutex_init(&rwlock->status_lock);
cond_init(&rwlock->reader_cv);
cond_init(&rwlock->writer_cv);
return 0;
}
/**
* @brief lock a rwlock
*/
void rwlock_lock(rwlock_t* rwlock, int type) {
mutex_lock(&rwlock->status_lock);
if (type == RWLOCK_READ) {
while (rwlock->status == RWLOCK_STATUS_WRITE) {
/* wait for the write to release */
cond_wait(&rwlock->reader_cv, &rwlock->status_lock);
}
rwlock->status = RWLOCK_STATUS_READ;
rwlock->num_reader++;
} else {
while (rwlock->status != RWLOCK_STATUS_UNLOCK) {
affirm(rwlock->status == RWLOCK_STATUS_WRITE);
/* wait for readers to release */
cond_wait(&rwlock->writer_cv, &rwlock->status_lock);
}
rwlock->status = RWLOCK_STATUS_WRITE;
}
mutex_unlock(&rwlock->status_lock);
}
/**
* @brief unlock a rwlock
*/
void rwlock_unlock(rwlock_t* rwlock) {
mutex_lock(&rwlock->status_lock);
if (rwlock->status == RWLOCK_STATUS_READ) {
rwlock->num_reader--;
/* the last reader should notify the writers */
if (rwlock->num_reader == 0) {
rwlock->status = RWLOCK_STATUS_UNLOCK;
cond_broadcast(&rwlock->writer_cv);
}
} else {
affirm(rwlock->status == RWLOCK_STATUS_WRITE);
rwlock->status = RWLOCK_STATUS_UNLOCK;
/* notify all readers */
cond_broadcast(&rwlock->reader_cv);
}
mutex_unlock(&rwlock->status_lock);
}
/**
* @brief destroy a rwlock
*/
void rwlock_destroy(rwlock_t* rwlock) {
affirm(rwlock->status == RWLOCK_STATUS_UNLOCK);
mutex_destroy(&rwlock->status_lock);
cond_destroy(&rwlock->reader_cv);
cond_destroy(&rwlock->writer_cv);
}
/**
* @brief downgrade a rwlock
*/
void rwlock_downgrade(rwlock_t* rwlock) {
affirm(rwlock->status == RWLOCK_STATUS_WRITE);
rwlock->status = RWLOCK_STATUS_READ;
cond_broadcast(&rwlock->reader_cv);
}
|