[dovecot-cvs] dovecot/src/lib file-lock.c, 1.9, 1.10 file-lock.h, 1.4, 1.5
tss at dovecot.org
tss at dovecot.org
Wed Dec 6 15:08:24 UTC 2006
Update of /var/lib/cvs/dovecot/src/lib
In directory talvi:/tmp/cvs-serv32161/lib
Modified Files:
file-lock.c file-lock.h
Log Message:
Lock handling changes. Everything goes through file-lock API now and there's
only a single enum listing the different lock methods. This change exposed
some unneeded (or possibly even wrong?) unlock calls in index file handling
which were fixed.
Index: file-lock.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/file-lock.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- file-lock.c 15 Aug 2004 03:40:31 -0000 1.9
+++ file-lock.c 6 Dec 2006 15:08:22 -0000 1.10
@@ -3,67 +3,161 @@
#include "lib.h"
#include "file-lock.h"
-#include <time.h>
-#include <signal.h>
+#ifdef HAVE_FLOCK
+# include <sys/file.h>
+#endif
-int file_try_lock(int fd, int lock_type)
-{
- return file_wait_lock_full(fd, lock_type, 0, NULL, NULL);
-}
+struct file_lock {
+ int fd;
+ char *path;
-int file_wait_lock(int fd, int lock_type)
+ int lock_type;
+ enum file_lock_method lock_method;
+};
+
+int file_try_lock(int fd, const char *path, int lock_type,
+ enum file_lock_method lock_method,
+ struct file_lock **lock_r)
{
- return file_wait_lock_full(fd, lock_type, DEFAULT_LOCK_TIMEOUT,
- NULL, NULL);
+ return file_wait_lock(fd, path, lock_type, lock_method, 0, lock_r);
}
-int file_wait_lock_full(int fd, int lock_type, unsigned int timeout,
- void (*callback)(unsigned int secs_left, void *context),
- void *context)
+static int file_lock_do(int fd, const char *path, int lock_type,
+ enum file_lock_method lock_method,
+ unsigned int timeout_secs)
{
- struct flock fl;
- time_t timeout_time, now;
- unsigned int next_alarm;
+ int ret;
- if (timeout == 0)
- timeout_time = 0;
- else {
- timeout_time = time(NULL) + timeout;
- alarm(I_MIN(timeout, 5));
- }
+ i_assert(fd != -1);
- fl.l_type = lock_type;
- fl.l_whence = SEEK_SET;
- fl.l_start = 0;
- fl.l_len = 0;
+ if (timeout_secs != 0)
+ alarm(timeout_secs);
- while (fcntl(fd, timeout != 0 ? F_SETLKW : F_SETLK, &fl) < 0) {
- if (timeout == 0 && (errno == EACCES || errno == EAGAIN)) {
- alarm(0);
- return 0;
- }
+ switch (lock_method) {
+ case FILE_LOCK_METHOD_FCNTL: {
+#ifndef HAVE_FCNTL
+ i_fatal("fcntl() locks not supported");
+#else
+ struct flock fl;
- if (errno != EINTR) {
- alarm(0);
- return -1;
+ fl.l_type = lock_type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+
+ ret = fcntl(fd, timeout_secs ? F_SETLKW : F_SETLK, &fl);
+ if (timeout_secs != 0) alarm(0);
+
+ if (ret == 0)
+ break;
+
+ if (timeout_secs == 0 &&
+ (errno == EACCES || errno == EAGAIN)) {
+ /* locked by another process */
+ return 0;
}
- now = time(NULL);
- if (timeout != 0 && now >= timeout_time) {
+ if (errno == EINTR) {
+ /* most likely alarm hit, meaning we timeouted.
+ even if not, we probably want to be killed
+ so stop blocking. */
errno = EAGAIN;
- alarm(0);
return 0;
}
+ i_error("fcntl() locking failed for file %s: %m", path);
+ abort();
+ return -1;
+#endif
+ }
+ case FILE_LOCK_METHOD_FLOCK: {
+#ifndef HAVE_FLOCK
+ i_fatal("flock() locks not supported");
+#else
+ int operation = timeout_secs != 0 ? 0 : LOCK_NB;
+
+ switch (lock_type) {
+ case F_RDLCK:
+ operation |= LOCK_SH;
+ break;
+ case F_WRLCK:
+ operation |= LOCK_EX;
+ break;
+ case F_UNLCK:
+ operation |= LOCK_UN;
+ break;
+ }
- next_alarm = (timeout_time - now) % 5;
- if (next_alarm == 0)
- next_alarm = 5;
- alarm(next_alarm);
+ ret = flock(fd, operation);
+ if (timeout_secs != 0) alarm(0);
- if (callback != NULL)
- callback(timeout_time - now, context);
+ if (ret == 0)
+ break;
+
+ if (errno == EWOULDBLOCK || errno == EINTR) {
+ /* a) locked by another process,
+ b) timeouted */
+ return 0;
+ }
+ i_error("flock() locking failed for file %s: %m", path);
+ return -1;
+#endif
+ }
+ case FILE_LOCK_METHOD_DOTLOCK:
+ /* we shouldn't get here */
+ i_unreached();
}
- alarm(0);
return 1;
}
+
+int file_wait_lock(int fd, const char *path, int lock_type,
+ enum file_lock_method lock_method,
+ unsigned int timeout_secs,
+ struct file_lock **lock_r)
+{
+ struct file_lock *lock;
+ int ret;
+
+ ret = file_lock_do(fd, path, lock_type, lock_method, timeout_secs);
+ if (ret <= 0)
+ return ret;
+
+ lock = i_new(struct file_lock, 1);
+ lock->fd = fd;
+ lock->path = i_strdup(path);
+ lock->lock_type = lock_type;
+ lock->lock_method = lock_method;
+ *lock_r = lock;
+ return 1;
+}
+
+int file_lock_try_update(struct file_lock *lock, int lock_type)
+{
+ return file_lock_do(lock->fd, lock->path, lock_type,
+ lock->lock_method, 0);
+}
+
+void file_unlock(struct file_lock **_lock)
+{
+ struct file_lock *lock = *_lock;
+
+ *_lock = NULL;
+
+ if (file_lock_do(lock->fd, lock->path, F_UNLCK,
+ lock->lock_method, 0) == 0) {
+ /* this shouldn't happen */
+ i_error("file_unlock(%s) failed: %m", lock->path);
+ }
+
+ file_lock_free(&lock);
+}
+
+void file_lock_free(struct file_lock **_lock)
+{
+ struct file_lock *lock = *_lock;
+
+ *_lock = NULL;
+
+ i_free(lock->path);
+ i_free(lock);
+}
Index: file-lock.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/file-lock.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- file-lock.h 11 Jan 2003 19:55:56 -0000 1.4
+++ file-lock.h 6 Dec 2006 15:08:22 -0000 1.5
@@ -6,19 +6,31 @@
#define DEFAULT_LOCK_TIMEOUT 120
-/* Lock whole file descriptor. Returns 1 if successful, 0 if lock failed,
- or -1 if error. lock_type is F_WRLCK, F_RDLCK or F_UNLCK. */
-int file_try_lock(int fd, int lock_type);
+struct file_lock;
-/* Lock whole file descriptor. Returns 1 if successful, 0 if timeout or
- -1 if error. When returning 0, errno is also set to EAGAIN. Timeouts after
- DEFAULT_LOCK_TIMEOUT. */
-int file_wait_lock(int fd, int lock_type);
+enum file_lock_method {
+ FILE_LOCK_METHOD_FCNTL,
+ FILE_LOCK_METHOD_FLOCK,
+ FILE_LOCK_METHOD_DOTLOCK
+};
-/* Like file_wait_lock(), but you can specify the timout and a callback which
- is called once in a while if waiting takes longer. */
-int file_wait_lock_full(int fd, int lock_type, unsigned int timeout,
- void (*callback)(unsigned int secs_left, void *context),
- void *context);
+/* Lock the file. Returns 1 if successful, 0 if file is already locked,
+ or -1 if error. lock_type is F_WRLCK or F_RDLCK. */
+int file_try_lock(int fd, const char *path, int lock_type,
+ enum file_lock_method lock_method,
+ struct file_lock **lock_r);
+/* Like lock_try_lock(), but return 0 only after having tried to lock for
+ timeout_secs. */
+int file_wait_lock(int fd, const char *path, int lock_type,
+ enum file_lock_method lock_method,
+ unsigned int timeout_secs,
+ struct file_lock **lock_r);
+/* Change the lock type. */
+int file_lock_try_update(struct file_lock *lock, int lock_type);
+
+/* Unlock and free the lock. */
+void file_unlock(struct file_lock **lock);
+/* Free the lock without unlocking it (because you're closing the fd anyway). */
+void file_lock_free(struct file_lock **lock);
#endif
More information about the dovecot-cvs
mailing list