aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/fossil/9excl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/fossil/9excl.c')
-rw-r--r--src/cmd/fossil/9excl.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/src/cmd/fossil/9excl.c b/src/cmd/fossil/9excl.c
new file mode 100644
index 00000000..6fce280a
--- /dev/null
+++ b/src/cmd/fossil/9excl.c
@@ -0,0 +1,126 @@
+#include "stdinc.h"
+
+#include "9.h"
+
+static struct {
+ VtLock* lock;
+
+ Excl* head;
+ Excl* tail;
+} ebox;
+
+struct Excl {
+ Fsys* fsys;
+ uvlong path;
+ ulong time;
+
+ Excl* next;
+ Excl* prev;
+};
+
+enum {
+ LifeTime = (5*60),
+};
+
+int
+exclAlloc(Fid* fid)
+{
+ ulong t;
+ Excl *excl;
+
+ assert(fid->excl == nil);
+
+ t = time(0L);
+ vtLock(ebox.lock);
+ for(excl = ebox.head; excl != nil; excl = excl->next){
+ if(excl->fsys != fid->fsys || excl->path != fid->qid.path)
+ continue;
+ /*
+ * Found it.
+ * Now, check if it's timed out.
+ * If not, return error, it's locked.
+ * If it has timed out, zap the old
+ * one and continue on to allocate a
+ * a new one.
+ */
+ if(excl->time >= t){
+ vtUnlock(ebox.lock);
+ vtSetError("exclusive lock");
+ return 0;
+ }
+ excl->fsys = nil;
+ }
+
+ /*
+ * Not found or timed-out.
+ * Alloc a new one and initialise.
+ */
+ excl = vtMemAllocZ(sizeof(Excl));
+ excl->fsys = fid->fsys;
+ excl->path = fid->qid.path;
+ excl->time = t+LifeTime;
+ if(ebox.tail != nil){
+ excl->prev = ebox.tail;
+ ebox.tail->next = excl;
+ }
+ else{
+ ebox.head = excl;
+ excl->prev = nil;
+ }
+ ebox.tail = excl;
+ excl->next = nil;
+ vtUnlock(ebox.lock);
+
+ fid->excl = excl;
+ return 1;
+}
+
+int
+exclUpdate(Fid* fid)
+{
+ ulong t;
+ Excl *excl;
+
+ excl = fid->excl;
+
+ t = time(0L);
+ vtLock(ebox.lock);
+ if(excl->time < t || excl->fsys != fid->fsys){
+ vtUnlock(ebox.lock);
+ vtSetError("exclusive lock broken");
+ return 0;
+ }
+ excl->time = t+LifeTime;
+ vtUnlock(ebox.lock);
+
+ return 1;
+}
+
+void
+exclFree(Fid* fid)
+{
+ Excl *excl;
+
+ if((excl = fid->excl) == nil)
+ return;
+ fid->excl = nil;
+
+ vtLock(ebox.lock);
+ if(excl->prev != nil)
+ excl->prev->next = excl->next;
+ else
+ ebox.head = excl->next;
+ if(excl->next != nil)
+ excl->next->prev = excl->prev;
+ else
+ ebox.tail = excl->prev;
+ vtUnlock(ebox.lock);
+
+ vtMemFree(excl);
+}
+
+void
+exclInit(void)
+{
+ ebox.lock = vtLockAlloc();
+}