… | |
… | |
46 | #define u_fsync(handle) FlushFileBuffers (handle) |
46 | #define u_fsync(handle) FlushFileBuffers (handle) |
47 | #define u_sync() |
47 | #define u_sync() |
48 | |
48 | |
49 | #define u_lockfile(path) CreateFile (path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) |
49 | #define u_lockfile(path) CreateFile (path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) |
50 | #define u_cloexec(handle) |
50 | #define u_cloexec(handle) |
51 | // acquire shared in addition to excl, then unlock excl |
|
|
52 | #define u_lock_write_to_read(wait) u_lock (U_LOCK_READ, 1); u_lock (U_UNLOCK, 1); |
|
|
53 | |
51 | |
54 | #else |
52 | #else |
55 | |
53 | |
56 | #define _GNU_SOURCE 1 |
54 | #define _GNU_SOURCE 1 |
57 | #define _BSD_SOURCE 1 |
55 | #define _BSD_SOURCE 1 |
58 | // the above increases our chances of getting MAP_ANONYMOUS |
56 | // the above increases our chances of getting MAP_ANONYMOUS |
59 | |
57 | |
60 | #include <sys/mman.h> |
58 | #include <sys/mman.h> |
61 | #include <sys/types.h> |
59 | #include <sys/types.h> |
|
|
60 | #include <sys/stat.h> |
|
|
61 | #include <unistd.h> |
62 | #include <pwd.h> |
62 | #include <pwd.h> |
63 | |
63 | |
64 | #if defined (MAP_ANON) && !defined (MAP_ANONYMOUS) |
64 | #if defined (MAP_ANON) && !defined (MAP_ANONYMOUS) |
65 | #define MAP_ANONYMOUS MAP_ANON |
65 | #define MAP_ANONYMOUS MAP_ANON |
66 | #endif |
66 | #endif |
… | |
… | |
89 | #define u_fsync(handle) |
89 | #define u_fsync(handle) |
90 | #define u_sync() sync () |
90 | #define u_sync() sync () |
91 | |
91 | |
92 | #define u_lockfile(path) open (path, O_RDWR | O_CREAT, 0666) |
92 | #define u_lockfile(path) open (path, O_RDWR | O_CREAT, 0666) |
93 | #define u_cloexec(handle) fcntl (handle, F_SETFD, FD_CLOEXEC) |
93 | #define u_cloexec(handle) fcntl (handle, F_SETFD, FD_CLOEXEC) |
94 | #define u_lock_write_to_read(wait) u_lock (U_LOCK_READ, 1); |
|
|
95 | |
94 | |
96 | #endif |
95 | #endif |
97 | |
96 | |
98 | #define u_16(ptr) (((ptr)[0] << 8) | (ptr)[1]) |
97 | #define u_16(ptr) (((ptr)[0] << 8) | (ptr)[1]) |
99 | #define u_32(ptr) (((ptr)[0] << 24) | ((ptr)[1] << 16) | ((ptr)[2] << 8) | (ptr)[3]) |
98 | #define u_32(ptr) (((ptr)[0] << 24) | ((ptr)[1] << 16) | ((ptr)[2] << 8) | (ptr)[3]) |
… | |
… | |
216 | if (!u_mkdir (tmppath)) |
215 | if (!u_mkdir (tmppath)) |
217 | return; |
216 | return; |
218 | } |
217 | } |
219 | } |
218 | } |
220 | |
219 | |
221 | enum |
220 | static u_handle |
|
|
221 | u_lock (const char *path, int excl, int dowait) |
222 | { |
222 | { |
223 | U_UNLOCK, |
223 | u_handle h; |
224 | U_LOCK_READ, |
|
|
225 | U_LOCK_WRITE |
|
|
226 | }; |
|
|
227 | |
224 | |
228 | static int |
225 | h = u_lockfile (path); |
229 | u_lock (int mode, int dowait) |
226 | if (!u_valid (h)) |
230 | { |
227 | return h; |
231 | #ifdef _WIN32 |
228 | |
232 | if (mode == U_UNLOCK) |
229 | u_cloexec (h); |
233 | return !UnlockFile (lock_handle, 0, 0, 1, 0); |
230 | |
234 | else |
231 | for (;;) |
235 | { |
232 | { |
|
|
233 | int success; |
|
|
234 | |
|
|
235 | // acquire the lock |
|
|
236 | #ifdef _WIN32 |
236 | OVERLAPPED ov = { 0 }; |
237 | OVERLAPPED ov = { 0 }; |
237 | |
238 | |
238 | return !LockFileEx (lock_handle, |
239 | success = LockFileEx (h, |
239 | 0 |
|
|
240 | | (mode == U_LOCK_WRITE ? LOCKFILE_EXCLUSIVE_LOCK : 0) |
240 | (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) |
241 | | (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), |
241 | | (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), |
242 | 0, |
242 | 0, |
243 | 1, 0, |
243 | 1, 0, |
244 | &ov); |
244 | &ov); |
245 | } |
|
|
246 | #else |
245 | #else |
247 | static short mode2lck [] = { F_UNLCK, F_RDLCK, F_WRLCK }; |
|
|
248 | struct flock lck; |
246 | struct flock lck = { 0 }; |
249 | lck.l_type = mode2lck [mode]; |
247 | |
|
|
248 | lck.l_type = excl ? F_WRLCK : F_RDLCK; |
250 | lck.l_whence = SEEK_SET; |
249 | lck.l_whence = SEEK_SET; |
251 | lck.l_start = 0; |
|
|
252 | lck.l_len = 1; |
250 | lck.l_len = 1; |
253 | |
251 | |
254 | return fcntl (lock_handle, dowait ? F_SETLKW : F_SETLK, &lck); |
252 | success = !fcntl (h, dowait ? F_SETLKW : F_SETLK, &lck); |
255 | #endif |
253 | #endif |
|
|
254 | |
|
|
255 | if (!success) |
|
|
256 | break; |
|
|
257 | |
|
|
258 | // we have the lock, now verify that the lockfile still exists |
|
|
259 | |
|
|
260 | #ifdef _WIN32 |
|
|
261 | // apparently, we have to open the file to get its info :( |
|
|
262 | BY_HANDLE_FILE_INFORMATION s1, s2; |
|
|
263 | u_handle h2 = u_lockfile (path); |
|
|
264 | if (!u_valid (h)) |
|
|
265 | break; |
|
|
266 | |
|
|
267 | success = GetFileInformationByHandle (h, &s1) |
|
|
268 | && GetFileInformationByHandle (h2, &s2); |
|
|
269 | |
|
|
270 | u_close (h2); |
|
|
271 | |
|
|
272 | if (!success) |
|
|
273 | break; |
|
|
274 | |
|
|
275 | success = s1.dwVolumeSerialNumber == s2.dwVolumeSerialNumber |
|
|
276 | && s1.nFileIndexHigh == s2.nFileIndexHigh |
|
|
277 | && s1.nFileIndexLow == s2.nFileIndexLow; |
|
|
278 | #else |
|
|
279 | struct stat s1, s2; |
|
|
280 | |
|
|
281 | if (fstat (h, &s1) || stat (path, &s2)) |
|
|
282 | break; |
|
|
283 | |
|
|
284 | success = s1.st_dev == s2.st_dev |
|
|
285 | && s1.st_ino == s2.st_ino; |
|
|
286 | #endif |
|
|
287 | |
|
|
288 | if (success) |
|
|
289 | return h; // lock successfully acquired |
|
|
290 | |
|
|
291 | // files differ, close and retry - should be very rare |
|
|
292 | u_close (h); |
|
|
293 | } |
|
|
294 | |
|
|
295 | // failure |
|
|
296 | u_close (h); |
|
|
297 | return u_invalid_handle; |
256 | } |
298 | } |
257 | |
299 | |
258 | static void |
300 | static void |
259 | systemv (const char *const argv[]) |
301 | systemv (const char *const argv[]) |
260 | { |
302 | { |
… | |
… | |
463 | strcpy (execdir, exe_dir); |
505 | strcpy (execdir, exe_dir); |
464 | u_append (execdir, "i-"); |
506 | u_append (execdir, "i-"); |
465 | strcat (execdir, exe_ver); |
507 | strcat (execdir, exe_ver); |
466 | |
508 | |
467 | strcat (strcpy (tmppath, execdir), ".lck"); |
509 | strcat (strcpy (tmppath, execdir), ".lck"); |
468 | lock_handle = u_lockfile (tmppath); |
510 | lock_handle = u_lock (tmppath, 0, 1); |
469 | if (!lock_handle) |
511 | if (!lock_handle) |
470 | fatal ("unable to create lock file"); |
512 | fatal ("unable to lock application instance"); |
471 | |
|
|
472 | u_cloexec (lock_handle); |
|
|
473 | |
|
|
474 | // all users that uee an instance acquire a shared lock |
|
|
475 | // acquiring an exclusive lock is enough to delete the dir |
|
|
476 | // deleeting the lockfile is another topic altogether |
|
|
477 | u_lock (U_LOCK_READ, 1); |
|
|
478 | |
513 | |
479 | if (access (execdir, F_OK)) |
514 | if (access (execdir, F_OK)) |
480 | { |
515 | { |
481 | // does not exist yet, so unpack and move |
516 | // does not exist yet, so unpack and move |
482 | tmpdir (exe_dir); |
517 | tmpdir (exe_dir); |