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