~kris/9p

9hist

ref: fbcfb82ea6cd5e69275bbca8cfb9fe1e33904487 9hist/power/lock.c -rw-r--r-- 2.1 KiB
fbcfb82e — David du Colombier Plan 9 from Bell Labs 1993-05-11 33 years ago
                                                                                
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
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

/*
 * The hardware semaphores are strange.  Only 64 per page can be used,
 * 1024 pages of them.  Only the low bit is meaningful.
 * Reading an unset semaphore sets the semaphore and returns the old value.
 * Writing a semaphore sets the value, so writing 0 resets (clears) the semaphore.
 */

enum
{
	SEMPERPG	= 64,		/* hardware semaphores per page */
	NSEMPG		= 1024,
	ULOCKPG		= 512,
};

struct
{
	Lock	lock;			/* lock to allocate */
	uchar	bmap[NSEMPG];		/* allocation map */
	int	ulockpg;		/* count of user lock available */
}semalloc;

Page lkpgheader[NSEMPG];
#define lhash(laddr)	((int)laddr>>2)&(((NSEMPG-ULOCKPG)*(BY2PG>>2))-1)&~0x3c0

void
lockinit(void)
{
	int *sbsem, h, i;

	/*
	 * Initialise the system semaphore hardware
	 */
	for(i = 0; i < (NSEMPG-ULOCKPG)*BY2PG; i += 4) {
		h = lhash(i);
		sbsem = (int*)SBSEM+h;
		*sbsem = 0;
	}
	semalloc.ulockpg = ULOCKPG;
}

/* equivalent of newpage for pages of hardware locks */
Page*
lkpage(Segment *s, ulong va)
{
	int i;
	Page *pg;
	uchar *p, *top;

	USED(s);
	lock(&semalloc.lock);
	if(--semalloc.ulockpg < 0) {
		semalloc.ulockpg++;
		unlock(&semalloc.lock);
		return 0;
	}
	top = &semalloc.bmap[NSEMPG];
	for(p = semalloc.bmap; p < top && *p; p++)
		;
	if(p >= top)
		panic("lkpage");

	*p = 1;
	i = p-semalloc.bmap;
	pg = &lkpgheader[i];
	pg->pa = (ulong)((i*WD2PG) + SBSEM) & ~UNCACHED;
	pg->va = va;
	pg->ref = 1;

	unlock(&semalloc.lock);
	return pg;
}

void
lkpgfree(Page *pg)
{
	uchar *p;

	lock(&semalloc.lock);
	p = &semalloc.bmap[((pg->pa|UNCACHED)-(ulong)SBSEM)/BY2PG];
	if(!*p)
		panic("lkpgfree");
	*p = 0;
	
	semalloc.ulockpg++;
	unlock(&semalloc.lock);
}

void
lock(Lock *lk)
{
	int *hwsem, hash;

	hash = lhash(lk);
	hwsem = (int*)SBSEM+hash;

	for(;;) {
		if(muxlock(hwsem, &lk->val))
			return;
		while(lk->val)
			;
	}
	print("lock loop %lux pc %lux held by pc %lux\n", lk, getcallerpc(lk), lk->pc);
	dumpstack();
}	

int
canlock(Lock *lk)
{
	int hash;

	hash = lhash(lk);
	return muxlock((int*)SBSEM+hash, &lk->val);
}

void
unlock(Lock *l)
{
	l->pc = 0;
	l->val = 0;
}