sq3: `transacted` uses scoped delegate
[iv.d.git] / lockfile.d
blob17ee3d89bfc700e1874b2ab7f1e376002df55487
1 /* Written by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License ONLY.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 module iv.lockfile /*is aliced*/;
18 import iv.alice;
21 // ////////////////////////////////////////////////////////////////////////// //
22 private struct LockFileImpl {
23 private:
24 uint rc;
25 char[] fname; // malloced, 0-terminated (but 0 is not in slice)
26 int fd;
27 bool locked;
29 public nothrow @nogc:
30 void kill () {
31 import core.stdc.stdlib : free;
32 import core.sys.posix.unistd : getpid, close;
33 assert(fd >= 0);
34 bool dorm = false;
35 if (locked) {
36 import core.sys.posix.fcntl;
37 flock lk;
38 lk.l_type = F_UNLCK;
39 lk.l_whence = 0/*SEEK_SET*/;
40 lk.l_start = 0;
41 lk.l_len = 0;
42 lk.l_pid = getpid();
43 fcntl(fd, F_SETLK, &lk);
44 locked = false;
45 dorm = true;
47 close(fd);
48 fd = -1;
49 if (dorm) {
50 import core.stdc.stdio : remove;
51 remove(fname.ptr);
53 free(fname.ptr);
54 fname = null;
57 // this will return `false` for already locked file!
58 bool tryLock () {
59 import core.sys.posix.fcntl;
60 import core.sys.posix.unistd : getpid;
61 assert(fd >= 0);
62 if (locked) return false;
63 flock lk;
64 lk.l_type = F_WRLCK;
65 lk.l_whence = 0/*SEEK_SET*/;
66 lk.l_start = 0;
67 lk.l_len = 0;
68 lk.l_pid = getpid();
69 if (fcntl(fd, F_SETLK/*W*/, &lk) == 0) locked = true;
70 return locked;
73 static:
74 usize create (const(char)[] afname) {
75 import core.sys.posix.fcntl /*: open*/;
76 import core.sys.posix.unistd : close;
77 import core.sys.posix.stdlib : malloc, free;
78 if (afname.length == 0) return 0;
79 auto namep = cast(char*)malloc(afname.length+1);
80 if (namep is null) return 0;
81 namep[0..afname.length+1] = 0;
82 namep[0..afname.length] = afname[];
83 auto xfd = open(namep, O_RDWR|O_CREAT/*|O_CLOEXEC*/, 0x1b6/*0o666*/);
84 if (xfd < 0) { free(namep); return 0; }
85 auto fimp = cast(ubyte*)malloc(LockFileImpl.sizeof);
86 if (fimp is null) { close(xfd); free(namep); return 0; }
87 fimp[0..LockFileImpl.sizeof] = 0;
88 auto res = cast(LockFileImpl*)fimp;
89 res.fname = namep[0..afname.length];
90 res.fd = xfd;
91 res.rc = 1;
92 return cast(usize)fimp;
97 // ////////////////////////////////////////////////////////////////////////// //
98 public struct LockFile {
99 private:
100 usize lci;
102 nothrow @trusted @nogc:
103 void decref () {
104 if (lci) {
105 auto lcp = cast(LockFileImpl*)lci;
106 if (--lcp.rc == 0) lcp.kill;
107 lci = 0;
111 public:
112 this (const(char)[] fname) { lci = LockFileImpl.create(fname); }
113 ~this () { pragma(inline, true); if (lci) decref(); }
114 this (this) { pragma(inline, true); if (lci) { ++(cast(LockFileImpl*)lci).rc; } }
115 void opAssign (in LockFile fl) {
116 if (fl.lci) ++(cast(LockFileImpl*)fl.lci).rc;
117 decref();
118 lci = fl.lci;
121 void close () { pragma(inline, true); if (lci != 0) decref(); }
123 @property bool valid () const pure { pragma(inline, true); return (lci != 0); }
124 @property bool locked () const pure { pragma(inline, true); return (lci != 0 ? (cast(LockFileImpl*)lci).locked : false); }
126 // this will return `false` for already locked file!
127 bool tryLock () { pragma(inline, true); return (lci == 0 ? false : (cast(LockFileImpl*)lci).tryLock); }
131 // ////////////////////////////////////////////////////////////////////////// //
133 __gshared LockFile prjLockFile;
134 prjLockFile = LockFile(pfn~".lock");
135 if (!prjLockFile.tryLock) {
136 prjLockFile.close();
137 return false;