--- Urlader/urlader.c 2011/12/30 12:21:28 1.6 +++ Urlader/urlader.c 2011/12/30 14:51:45 1.7 @@ -48,8 +48,6 @@ #define u_lockfile(path) CreateFile (path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) #define u_cloexec(handle) - // acquire shared in addition to excl, then unlock excl - #define u_lock_write_to_read(wait) u_lock (U_LOCK_READ, 1); u_lock (U_UNLOCK, 1); #else @@ -59,6 +57,8 @@ #include #include + #include + #include #include #if defined (MAP_ANON) && !defined (MAP_ANONYMOUS) @@ -91,7 +91,6 @@ #define u_lockfile(path) open (path, O_RDWR | O_CREAT, 0666) #define u_cloexec(handle) fcntl (handle, F_SETFD, FD_CLOEXEC) - #define u_lock_write_to_read(wait) u_lock (U_LOCK_READ, 1); #endif @@ -218,41 +217,84 @@ } } -enum +static u_handle +u_lock (const char *path, int excl, int dowait) { - U_UNLOCK, - U_LOCK_READ, - U_LOCK_WRITE -}; + u_handle h; -static int -u_lock (int mode, int dowait) -{ -#ifdef _WIN32 - if (mode == U_UNLOCK) - return !UnlockFile (lock_handle, 0, 0, 1, 0); - else + h = u_lockfile (path); + if (!u_valid (h)) + return h; + + u_cloexec (h); + + for (;;) { + int success; + + // acquire the lock +#ifdef _WIN32 OVERLAPPED ov = { 0 }; - return !LockFileEx (lock_handle, - 0 - | (mode == U_LOCK_WRITE ? LOCKFILE_EXCLUSIVE_LOCK : 0) - | (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), - 0, - 1, 0, - &ov); - } + success = LockFileEx (h, + (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) + | (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), + 0, + 1, 0, + &ov); +#else + struct flock lck = { 0 }; + + lck.l_type = excl ? F_WRLCK : F_RDLCK; + lck.l_whence = SEEK_SET; + lck.l_len = 1; + + success = !fcntl (h, dowait ? F_SETLKW : F_SETLK, &lck); +#endif + + if (!success) + break; + + // we have the lock, now verify that the lockfile still exists + +#ifdef _WIN32 + // apparently, we have to open the file to get its info :( + BY_HANDLE_FILE_INFORMATION s1, s2; + u_handle h2 = u_lockfile (path); + if (!u_valid (h)) + break; + + success = GetFileInformationByHandle (h, &s1) + && GetFileInformationByHandle (h2, &s2); + + u_close (h2); + + if (!success) + break; + + success = s1.dwVolumeSerialNumber == s2.dwVolumeSerialNumber + && s1.nFileIndexHigh == s2.nFileIndexHigh + && s1.nFileIndexLow == s2.nFileIndexLow; #else - static short mode2lck [] = { F_UNLCK, F_RDLCK, F_WRLCK }; - struct flock lck; - lck.l_type = mode2lck [mode]; - lck.l_whence = SEEK_SET; - lck.l_start = 0; - lck.l_len = 1; + struct stat s1, s2; - return fcntl (lock_handle, dowait ? F_SETLKW : F_SETLK, &lck); + if (fstat (h, &s1) || stat (path, &s2)) + break; + + success = s1.st_dev == s2.st_dev + && s1.st_ino == s2.st_ino; #endif + + if (success) + return h; // lock successfully acquired + + // files differ, close and retry - should be very rare + u_close (h); + } + + // failure + u_close (h); + return u_invalid_handle; } static void @@ -465,16 +507,9 @@ strcat (execdir, exe_ver); strcat (strcpy (tmppath, execdir), ".lck"); - lock_handle = u_lockfile (tmppath); + lock_handle = u_lock (tmppath, 0, 1); if (!lock_handle) - fatal ("unable to create lock file"); - - u_cloexec (lock_handle); - - // all users that uee an instance acquire a shared lock - // acquiring an exclusive lock is enough to delete the dir - // deleeting the lockfile is another topic altogether - u_lock (U_LOCK_READ, 1); + fatal ("unable to lock application instance"); if (access (execdir, F_OK)) {