-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmutexOpMap.go
168 lines (132 loc) · 3.79 KB
/
mutexOpMap.go
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package muSupervisor
import (
"fmt"
"log"
)
type mutexOpMap map[*supervisedMutex]opMap
type reqQueue struct {
read map[routineNum]*opData
rw map[routineNum]*opData
}
func newReqQueue() reqQueue {
return reqQueue{
read: make(map[routineNum]*opData),
rw: make(map[routineNum]*opData),
}
}
func newOpMap() opMap {
return opMap{
pending: newReqQueue(),
active: newReqQueue(),
done: make(map[routineNum]*opData),
doneRWait: make(map[routineNum]*opData),
}
}
func (m mutexOpMap) mapRequest(d *opData) {
var pendingQueue map[routineNum]*opData
_, mutexExists := m[d.mutexPtr]
if !mutexExists {
m[d.mutexPtr] = newOpMap()
}
switch d.t {
case RLOCK:
pendingQueue = m[d.mutexPtr].pending.read
case LOCK:
pendingQueue = m[d.mutexPtr].pending.rw
}
if previous, exists := pendingQueue[d.numRoutine]; exists {
fmt.Printf("FATAL: muSupervisor: lock already requested on the same routine %d.\n", d.numRoutine)
logOpDetails(previous)
logOpDetails(d)
log.Fatal("Exiting")
}
d.state = PENDING
pendingQueue[d.numRoutine] = d
}
func (m mutexOpMap) mapObtained(d *opData) {
// We always expect to enter here on the same routine and same *opData pointer.
var pendingQueue, activeQueue map[routineNum]*opData
switch d.t {
case RLOCK:
if len(m[d.mutexPtr].active.rw) != 0 {
log.Fatal("ERROR: active rw lock when obtaining read lock.\n")
}
pendingQueue = m[d.mutexPtr].pending.read
activeQueue = m[d.mutexPtr].active.read
case LOCK:
if len(m[d.mutexPtr].active.rw) != 0 {
log.Fatal("ERROR: active ops not empty when obtaining lock.\n")
}
if len(m[d.mutexPtr].active.read) != 0 {
log.Fatal("ERROR: read active ops not empty when obtaining lock.\n")
}
pendingQueue = m[d.mutexPtr].pending.rw
activeQueue = m[d.mutexPtr].active.rw
}
pendOp, exists := pendingQueue[d.numRoutine]
if !exists {
log.Fatalf("ERROR: no pending op found for routine %d when obtaining lock.\n", d.numRoutine)
}
pendOp.state = ACTIVE
activeQueue[d.numRoutine] = pendOp
delete(pendingQueue, d.numRoutine)
}
func (m mutexOpMap) mapUnlock(d *opData) {
var lockRt routineNum
//TODO: see supervisedMutex.go, track the unlock better if needed.
// unlockRt := d.numRoutine
var activeQueue, doneQueue map[routineNum]*opData
var destState opState
switch d.t {
case RUNLOCK:
if len(m[d.mutexPtr].active.read) < 1 {
log.Fatalf("ERROR: no read op active was found when runlocking.\n")
}
activeQueue = m[d.mutexPtr].active.read
// if we find the same routine that locked, we're sure (?) is the one being unlocked
if _, found := activeQueue[d.numRoutine]; found {
lockRt = d.numRoutine
doneQueue = m[d.mutexPtr].done // In this case, we're positive that this operation is done
destState = DONE
} else {
// otherwise, we currently can't track which routine did the lock. We randomly pick the first one.
for lockRtNum := range activeQueue {
lockRt = lockRtNum
break
}
doneQueue = m[d.mutexPtr].doneRWait
destState = DONERWAIT
}
case UNLOCK:
if len(m[d.mutexPtr].active.rw) != 1 {
log.Fatalf("ERROR: no single rw ops active was found when unlocking.\n")
}
activeQueue = m[d.mutexPtr].active.rw
doneQueue = m[d.mutexPtr].done
for lockRtNum := range activeQueue {
lockRt = lockRtNum
}
destState = DONE
}
activeOp := activeQueue[lockRt]
activeOp.state = destState
delete(activeQueue, lockRt)
doneQueue[lockRt] = activeOp
if (d.t == RUNLOCK) && (len(activeQueue) == 0) {
// All read locks are done, so we can move to the done queue.
for rtNum, op := range m[d.mutexPtr].doneRWait {
delete(m[d.mutexPtr].doneRWait, rtNum)
op.state = DONE
m[d.mutexPtr].done[rtNum] = op
}
}
}
func (m mutexOpMap) doCheck() {
for k, om := range m {
om.checkPending()
isEmpty := om.cleanup()
if isEmpty {
delete(m, k)
}
}
}