(locks[i].lock_type & G_LOCK_PENDING) ?
"(pending)" : "(owner)"));
+ if (((locks[i].lock_type & G_LOCK_PENDING) == 0)
+ && !process_exists(locks[i].pid)) {
+
+ DEBUGADD(10, ("lock owner %s died -- discarding\n",
+ procid_str(talloc_tos(),
+ &locks[i].pid)));
+
+ if (i < (num_locks-1)) {
+ locks[i] = locks[num_locks-1];
+ }
+ num_locks -= 1;
+ }
+ }
+
+ *plocks = locks;
+ *pnum_locks = num_locks;
+ return true;
+}
+
+static void g_lock_cleanup(int *pnum_locks, struct g_lock_rec *locks)
+{
+ int i, num_locks;
+
+ num_locks = *pnum_locks;
+
+ DEBUG(10, ("g_lock_cleanup: %d locks\n", num_locks));
+
+ for (i=0; i<num_locks; i++) {
if (process_exists(locks[i].pid)) {
continue;
}
}
num_locks -= 1;
}
-
- *plocks = locks;
*pnum_locks = num_locks;
- return true;
+ return;
}
static struct g_lock_rec *g_lock_addrec(TALLOC_CTX *mem_ctx,
locks[our_index].lock_type = lock_type;
}
+ if (NT_STATUS_IS_OK(status) && ((lock_type & G_LOCK_PENDING) == 0)) {
+ /*
+ * Walk through the list of locks, search for dead entries
+ */
+ g_lock_cleanup(&num_locks, locks);
+ }
+
data = make_tdb_data((uint8_t *)locks, num_locks * sizeof(*locks));
store_status = rec->store(rec, data, 0);
if (!NT_STATUS_IS_OK(store_status)) {
NTSTATUS status;
bool retry = false;
struct timeval timeout_end;
- struct timeval timeout_remaining;
struct timeval time_now;
DEBUG(10, ("Trying to acquire lock %d for %s\n", (int)lock_type,
fd_set *r_fds = NULL;
int max_fd = 0;
int ret;
+ struct timeval select_timeout;
status = g_lock_trylock(ctx, name, lock_type);
if (NT_STATUS_IS_OK(status)) {
}
#endif
- time_now = timeval_current();
- timeout_remaining = timeval_until(&time_now, &timeout_end);
+ select_timeout = timeval_set(60, 0);
ret = sys_select(max_fd + 1, r_fds, NULL, NULL,
- &timeout_remaining);
-
+ &select_timeout);
if (ret == -1) {
if (errno != EINTR) {
DEBUG(1, ("error calling select: %s\n",
break;
} else {
DEBUG(10, ("select returned 0 but timeout not "
- "not expired: strange - retrying\n"));
+ "not expired, retrying\n"));
}
} else if (ret != 1) {
DEBUG(1, ("invalid return code of select: %d\n", ret));
goto done;
}
+ TALLOC_FREE(rec);
+
if ((lock_type & G_LOCK_PENDING) == 0) {
+ int num_wakeups = 0;
+
/*
- * We've been the lock holder. Tell all others to retry.
+ * We've been the lock holder. Others to retry. Don't
+ * tell all others to avoid a thundering herd. In case
+ * this leads to a complete stall because we miss some
+ * processes, the loop in g_lock_lock tries at least
+ * once a minute.
*/
+
for (i=0; i<num_locks; i++) {
if ((locks[i].lock_type & G_LOCK_PENDING) == 0) {
continue;
}
+ if (!process_exists(locks[i].pid)) {
+ continue;
+ }
/*
* Ping all waiters to retry
procid_str(talloc_tos(),
&locks[i].pid),
nt_errstr(status)));
+ } else {
+ num_wakeups += 1;
+ }
+ if (num_wakeups > 5) {
+ break;
}
}
}
done:
+ /*
+ * For the error path, TALLOC_FREE(rec) as well. In the good
+ * path we have already freed it.
+ */
+ TALLOC_FREE(rec);
TALLOC_FREE(locks);
- TALLOC_FREE(rec);
return status;
}