lockfile.c: Adding mechanism to take a lock of a file after a given amount on time. even if the file is locked.
This commit is contained in:
parent
d779db6715
commit
61cad77a0c
1 changed files with 41 additions and 8 deletions
49
lockfile.c
49
lockfile.c
|
|
@ -22,6 +22,7 @@
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
@ -31,6 +32,11 @@
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "lockfile.h"
|
#include "lockfile.h"
|
||||||
|
|
||||||
|
/* Maximum time a lockfile can be uhm.. locked (in seconds)
|
||||||
|
Used to prevent deadlocks when processes "forgets" to unlock. */
|
||||||
|
|
||||||
|
#define MAX_LOCK_TIME (15 * 60) /* 15 min is fine. */
|
||||||
|
|
||||||
static struct lockfile *active_locks;
|
static struct lockfile *active_locks;
|
||||||
|
|
||||||
static void release_all_locks() {
|
static void release_all_locks() {
|
||||||
|
|
@ -94,28 +100,55 @@ static inline void init(void) {
|
||||||
is_init = 1;
|
is_init = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double get_lock_time(const char *path) {
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (stat(path, &st) < 0)
|
||||||
|
return -1;
|
||||||
|
return difftime(time(NULL), st.st_ctime);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_lock(const char *path, int force) {
|
||||||
|
|
||||||
|
int fd, mask = O_WRONLY | O_TRUNC | O_CREAT | O_EXCL;
|
||||||
|
|
||||||
|
if (force)
|
||||||
|
mask &= ~O_EXCL;
|
||||||
|
|
||||||
|
fd = open(path, mask, 0600);
|
||||||
|
if (fd < 0) {
|
||||||
|
/* Force open if lockfile exists
|
||||||
|
and MAX_LOCK_TIME is exceeded */
|
||||||
|
if (errno == EEXIST
|
||||||
|
&& get_lock_time(path) > MAX_LOCK_TIME) {
|
||||||
|
|
||||||
|
mask &= ~O_EXCL;
|
||||||
|
return open(path, mask, 0600);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
int hold_lock(struct lockfile *lock, const char *filename, int force) {
|
int hold_lock(struct lockfile *lock, const char *filename, int force) {
|
||||||
|
|
||||||
int rc, mask = O_WRONLY | O_CREAT | O_TRUNC;
|
int rc;
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
if (is_locked(lock))
|
if (is_locked(lock))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!force)
|
|
||||||
mask |= O_EXCL;
|
|
||||||
|
|
||||||
rc = snprintf(lock->name, sizeof(lock->name), "%s.lock", filename);
|
rc = snprintf(lock->name, sizeof(lock->name), "%s.lock", filename);
|
||||||
if (rc > sizeof(lock->name))
|
if (rc > sizeof(lock->name))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
lock->fd = open(lock->name, mask, 0600);
|
lock->fd = open_lock(lock->name, force);
|
||||||
if (lock->fd < 0) {
|
if (lock->fd < 0) {
|
||||||
return error(errno == EEXIST ?
|
return error(errno == EEXIST ? "'%s' is locked" :
|
||||||
"'%s' is locked" : "unable to create lockfile '%s'",
|
"unable to create lockfile '%s'", lock->name);
|
||||||
lock->name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lock->next = active_locks;
|
lock->next = active_locks;
|
||||||
active_locks = lock;
|
active_locks = lock;
|
||||||
return lock->fd;
|
return lock->fd;
|
||||||
|
|
|
||||||
Reference in a new issue