cosmetix
[iv.d.git] / lockfile.d
blobc177113b1691ff0fe591926b7c7c82ffefbc6b8b
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, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module iv.lockfile /*is aliced*/;
19 import iv.alice;
22 // ////////////////////////////////////////////////////////////////////////// //
23 private struct LockFileImpl {
24 private:
25 uint rc;
26 char[] fname; // malloced, 0-terminated (but 0 is not in slice)
27 int fd;
28 bool locked;
30 public nothrow @nogc:
31 void kill () {
32 import core.stdc.stdlib : free;
33 import core.sys.posix.unistd : getpid, close;
34 assert(fd >= 0);
35 bool dorm = false;
36 if (locked) {
37 import core.sys.posix.fcntl;
38 flock lk;
39 lk.l_type = F_UNLCK;
40 lk.l_whence = 0/*SEEK_SET*/;
41 lk.l_start = 0;
42 lk.l_len = 0;
43 lk.l_pid = getpid();
44 fcntl(fd, F_SETLK, &lk);
45 locked = false;
46 dorm = true;
48 close(fd);
49 fd = -1;
50 if (dorm) {
51 import core.stdc.stdio : remove;
52 remove(fname.ptr);
54 free(fname.ptr);
55 fname = null;
58 // this will return `false` for already locked file!
59 bool tryLock () {
60 import core.sys.posix.fcntl;
61 import core.sys.posix.unistd : getpid;
62 assert(fd >= 0);
63 if (locked) return false;
64 flock lk;
65 lk.l_type = F_WRLCK;
66 lk.l_whence = 0/*SEEK_SET*/;
67 lk.l_start = 0;
68 lk.l_len = 0;
69 lk.l_pid = getpid();
70 if (fcntl(fd, F_SETLK/*W*/, &lk) == 0) locked = true;
71 return locked;
74 static:
75 usize create (const(char)[] afname) {
76 import core.sys.posix.fcntl /*: open*/;
77 import core.sys.posix.unistd : close;
78 import core.sys.posix.stdlib : malloc, free;
79 if (afname.length == 0) return 0;
80 auto namep = cast(char*)malloc(afname.length+1);
81 if (namep is null) return 0;
82 namep[0..afname.length+1] = 0;
83 namep[0..afname.length] = afname[];
84 auto xfd = open(namep, O_RDWR|O_CREAT/*|O_CLOEXEC*/, 0x1b6/*0o666*/);
85 if (xfd < 0) { free(namep); return 0; }
86 auto fimp = cast(ubyte*)malloc(LockFileImpl.sizeof);
87 if (fimp is null) { close(xfd); free(namep); return 0; }
88 fimp[0..LockFileImpl.sizeof] = 0;
89 auto res = cast(LockFileImpl*)fimp;
90 res.fname = namep[0..afname.length];
91 res.fd = xfd;
92 res.rc = 1;
93 return cast(usize)fimp;
98 // ////////////////////////////////////////////////////////////////////////// //
99 public struct LockFile {
100 private:
101 usize lci;
103 nothrow @trusted @nogc:
104 void decref () {
105 if (lci) {
106 auto lcp = cast(LockFileImpl*)lci;
107 if (--lcp.rc == 0) lcp.kill;
108 lci = 0;
112 public:
113 this (const(char)[] fname) { lci = LockFileImpl.create(fname); }
114 ~this () { pragma(inline, true); if (lci) decref(); }
115 this (this) { pragma(inline, true); if (lci) { ++(cast(LockFileImpl*)lci).rc; } }
116 void opAssign (in LockFile fl) {
117 if (fl.lci) ++(cast(LockFileImpl*)fl.lci).rc;
118 decref();
119 lci = fl.lci;
122 void close () { pragma(inline, true); if (lci != 0) decref(); }
124 @property bool valid () const pure { pragma(inline, true); return (lci != 0); }
125 @property bool locked () const pure { pragma(inline, true); return (lci != 0 ? (cast(LockFileImpl*)lci).locked : false); }
127 // this will return `false` for already locked file!
128 bool tryLock () { pragma(inline, true); return (lci == 0 ? false : (cast(LockFileImpl*)lci).tryLock); }
132 // ////////////////////////////////////////////////////////////////////////// //
134 __gshared LockFile prjLockFile;
135 prjLockFile = LockFile(pfn~".lock");
136 if (!prjLockFile.tryLock) {
137 prjLockFile.close();
138 return false;