1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 7 struct { 8 ulong rlock; 9 ulong rlockq; 10 ulong wlock; 11 ulong wlockq; 12 ulong qlock; 13 ulong qlockq; 14 } rwstats; 15 16 void 17 qlock(QLock *q) 18 { 19 Proc *p; 20 21 if(m->ilockdepth != 0) 22 print("qlock: %lux: ilockdepth %d\n", getcallerpc(&q), m->ilockdepth); 23 if(up != nil && up->nlocks.ref) 24 print("qlock: %lux: nlocks %lud\n", getcallerpc(&q), up->nlocks.ref); 25 26 if(q->use.key == 0x55555555) 27 panic("qlock: q %p, key 5*\n", q); 28 lock(&q->use); 29 rwstats.qlock++; 30 if(!q->locked) { 31 q->locked = 1; 32 unlock(&q->use); 33 return; 34 } 35 if(up == 0) 36 panic("qlock"); 37 rwstats.qlockq++; 38 p = q->tail; 39 if(p == 0) 40 q->head = up; 41 else 42 p->qnext = up; 43 q->tail = up; 44 up->qnext = 0; 45 up->state = Queueing; 46 up->qpc = getcallerpc(&q); 47 unlock(&q->use); 48 sched(); 49 } 50 51 int 52 canqlock(QLock *q) 53 { 54 if(!canlock(&q->use)) 55 return 0; 56 if(q->locked){ 57 unlock(&q->use); 58 return 0; 59 } 60 q->locked = 1; 61 unlock(&q->use); 62 return 1; 63 } 64 65 void 66 qunlock(QLock *q) 67 { 68 Proc *p; 69 70 lock(&q->use); 71 if (q->locked == 0) 72 print("qunlock called with qlock not held, from %#p\n", 73 getcallerpc(&q)); 74 p = q->head; 75 if(p){ 76 q->head = p->qnext; 77 if(q->head == 0) 78 q->tail = 0; 79 unlock(&q->use); 80 ready(p); 81 return; 82 } 83 q->locked = 0; 84 unlock(&q->use); 85 } 86 87 void 88 rlock(RWlock *q) 89 { 90 Proc *p; 91 92 lock(&q->use); 93 rwstats.rlock++; 94 if(q->writer == 0 && q->head == nil){ 95 /* no writer, go for it */ 96 q->readers++; 97 unlock(&q->use); 98 return; 99 } 100 101 rwstats.rlockq++; 102 p = q->tail; 103 if(up == nil) 104 panic("rlock"); 105 if(p == 0) 106 q->head = up; 107 else 108 p->qnext = up; 109 q->tail = up; 110 up->qnext = 0; 111 up->state = QueueingR; 112 unlock(&q->use); 113 sched(); 114 } 115 116 void 117 runlock(RWlock *q) 118 { 119 Proc *p; 120 121 lock(&q->use); 122 p = q->head; 123 if(--(q->readers) > 0 || p == nil){ 124 unlock(&q->use); 125 return; 126 } 127 128 /* start waiting writer */ 129 if(p->state != QueueingW) 130 panic("runlock"); 131 q->head = p->qnext; 132 if(q->head == 0) 133 q->tail = 0; 134 q->writer = 1; 135 unlock(&q->use); 136 ready(p); 137 } 138 139 void 140 wlock(RWlock *q) 141 { 142 Proc *p; 143 144 lock(&q->use); 145 rwstats.wlock++; 146 if(q->readers == 0 && q->writer == 0){ 147 /* noone waiting, go for it */ 148 q->wpc = getcallerpc(&q); 149 q->wproc = up; 150 q->writer = 1; 151 unlock(&q->use); 152 return; 153 } 154 155 /* wait */ 156 rwstats.wlockq++; 157 p = q->tail; 158 if(up == nil) 159 panic("wlock"); 160 if(p == nil) 161 q->head = up; 162 else 163 p->qnext = up; 164 q->tail = up; 165 up->qnext = 0; 166 up->state = QueueingW; 167 unlock(&q->use); 168 sched(); 169 } 170 171 void 172 wunlock(RWlock *q) 173 { 174 Proc *p; 175 176 lock(&q->use); 177 p = q->head; 178 if(p == nil){ 179 q->writer = 0; 180 unlock(&q->use); 181 return; 182 } 183 if(p->state == QueueingW){ 184 /* start waiting writer */ 185 q->head = p->qnext; 186 if(q->head == nil) 187 q->tail = nil; 188 unlock(&q->use); 189 ready(p); 190 return; 191 } 192 193 if(p->state != QueueingR) 194 panic("wunlock"); 195 196 /* waken waiting readers */ 197 while(q->head != nil && q->head->state == QueueingR){ 198 p = q->head; 199 q->head = p->qnext; 200 q->readers++; 201 ready(p); 202 } 203 if(q->head == nil) 204 q->tail = nil; 205 q->writer = 0; 206 unlock(&q->use); 207 } 208 209 /* same as rlock but punts if there are any writers waiting */ 210 int 211 canrlock(RWlock *q) 212 { 213 lock(&q->use); 214 rwstats.rlock++; 215 if(q->writer == 0 && q->head == nil){ 216 /* no writer, go for it */ 217 q->readers++; 218 unlock(&q->use); 219 return 1; 220 } 221 unlock(&q->use); 222 return 0; 223 } 224