mbox-lock.c revision cfddb734b85ceaf49451d2f68aaad64a860ca6f6
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski/* Copyright (C) 2002 Timo Sirainen */
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski/* 0.1 .. 0.2msec */
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski/* lock methods to use in wanted order */
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski/* lock timeout */
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski/* assume stale dotlock if mbox file hasn't changed for n seconds */
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (120)
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski int (*func)(struct mbox_lock_context *ctx, int lock_type,
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic bool lock_settings_initialized = FALSE;
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic int lock_timeout, dotlock_change_timeout;
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic int mbox_unlock_files(struct mbox_lock_context *ctx);
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowskistatic void mbox_read_lock_methods(const char *str, const char *env,
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski const char *const *lock;
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski for (type = 0; lock_data[type].name != NULL; type++) {
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski if (strcasecmp(*lock, lock_data[type].name) == 0) {
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski i_fatal("%s: Invalid value %s", env, *lock);
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski for (i = 0; i < dest; i++) {
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski i_fatal("%s: Duplicated value %s", env, *lock);
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski /* @UNSAFE */
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski /* check that read/write list orders match. write_locks must contain
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski at least read_locks and possibly more. */
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski if (read_locks[r] == (enum mbox_lock_type)-1)
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski if (read_locks[r] != (enum mbox_lock_type)-1) {
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski i_fatal("mbox read/write lock list settings are invalid. "
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski "Lock ordering must be the same with both, "
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski "and write locks must contain all read locks "
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski "(and possibly more)");
cbc7f7ea90538f481b528959e9b6cf837b0dd785Till Mossakowski lock_timeout = str == NULL ? DEFAULT_LOCK_TIMEOUT : atoi(str);
return FALSE;
return TRUE;
int ret;
if (ret < 0) {
if (ret == 0) {
#ifdef HAVE_FLOCK
last_notify = 0;
#ifdef HAVE_LOCKF
last_notify = 0;
unsigned int next_alarm;
int wait_type;
if (max_wait_time == 0) {
alarm(0);
alarm(0);
if (next_alarm == 0)
alarm(0);
if (ret <= 0)
return ret;
int ret, i;
bool drop_locks;
for (i = 0; i < MBOX_LOCK_COUNT; i++)
if (ret <= 0) {
if (!drop_locks)
if (ret == 0) {
return ret;
if (drop_locks) {
unsigned int *lock_id_r)
int ret;
if (ret <= 0)
return ret;
int ret = 0;
return ret;
for (i = 0; i < MBOX_LOCK_COUNT; i++)