xref: /plan9/sys/src/cmd/fossil/9excl.c (revision e12a987081f10894b49298514b3a97b41db862b0)
1 #include "stdinc.h"
2 
3 #include "9.h"
4 
5 static struct {
6 	VtLock*	lock;
7 
8 	Excl*	head;
9 	Excl*	tail;
10 } ebox;
11 
12 struct Excl {
13 	Fsys*	fsys;
14 	uvlong	path;
15 	ulong	time;
16 
17 	Excl*	next;
18 	Excl*	prev;
19 };
20 
21 enum {
22 	LifeTime	= (5*60),
23 };
24 
25 int
exclAlloc(Fid * fid)26 exclAlloc(Fid* fid)
27 {
28 	ulong t;
29 	Excl *excl;
30 
31 	assert(fid->excl == nil);
32 
33 	t = time(0L);
34 	vtLock(ebox.lock);
35 	for(excl = ebox.head; excl != nil; excl = excl->next){
36 		if(excl->fsys != fid->fsys || excl->path != fid->qid.path)
37 			continue;
38 		/*
39 		 * Found it.
40 		 * Now, check if it's timed out.
41 		 * If not, return error, it's locked.
42 		 * If it has timed out, zap the old
43 		 * one and continue on to allocate a
44 		 * a new one.
45 		 */
46 		if(excl->time >= t){
47 			vtUnlock(ebox.lock);
48 			vtSetError("exclusive lock");
49 			return 0;
50 		}
51 		excl->fsys = nil;
52 	}
53 
54 	/*
55 	 * Not found or timed-out.
56 	 * Alloc a new one and initialise.
57 	 */
58 	excl = vtMemAllocZ(sizeof(Excl));
59 	excl->fsys = fid->fsys;
60 	excl->path = fid->qid.path;
61 	excl->time = t+LifeTime;
62 	if(ebox.tail != nil){
63 		excl->prev = ebox.tail;
64 		ebox.tail->next = excl;
65 	}
66 	else{
67 		ebox.head = excl;
68 		excl->prev = nil;
69 	}
70 	ebox.tail = excl;
71 	excl->next = nil;
72 	vtUnlock(ebox.lock);
73 
74 	fid->excl = excl;
75 	return 1;
76 }
77 
78 int
exclUpdate(Fid * fid)79 exclUpdate(Fid* fid)
80 {
81 	ulong t;
82 	Excl *excl;
83 
84 	excl = fid->excl;
85 
86 	t = time(0L);
87 	vtLock(ebox.lock);
88 	if(excl->time < t || excl->fsys != fid->fsys){
89 		vtUnlock(ebox.lock);
90 		vtSetError("exclusive lock broken");
91 		return 0;
92 	}
93 	excl->time = t+LifeTime;
94 	vtUnlock(ebox.lock);
95 
96 	return 1;
97 }
98 
99 void
exclFree(Fid * fid)100 exclFree(Fid* fid)
101 {
102 	Excl *excl;
103 
104 	if((excl = fid->excl) == nil)
105 		return;
106 	fid->excl = nil;
107 
108 	vtLock(ebox.lock);
109 	if(excl->prev != nil)
110 		excl->prev->next = excl->next;
111 	else
112 		ebox.head = excl->next;
113 	if(excl->next != nil)
114 		excl->next->prev = excl->prev;
115 	else
116 		ebox.tail = excl->prev;
117 	vtUnlock(ebox.lock);
118 
119 	vtMemFree(excl);
120 }
121 
122 void
exclInit(void)123 exclInit(void)
124 {
125 	ebox.lock = vtLockAlloc();
126 }
127