vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

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 }