summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/tdb/common/lock.c59
1 files changed, 39 insertions, 20 deletions
diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c
index 16963df097..25ed877900 100644
--- a/lib/tdb/common/lock.c
+++ b/lib/tdb/common/lock.c
@@ -198,14 +198,42 @@ int tdb_brunlock(struct tdb_context *tdb,
}
/*
- upgrade a read lock to a write lock. This needs to be handled in a
- special way as some OSes (such as solaris) have too conservative
- deadlock detection and claim a deadlock when progress can be
- made. For those OSes we may loop for a while.
+ * Do a tdb_brlock in a loop. Some OSes (such as solaris) have too
+ * conservative deadlock detection and claim a deadlock when progress can be
+ * made. For those OSes we may loop for a while.
+ */
+
+static int tdb_brlock_retry(struct tdb_context *tdb,
+ int rw_type, tdb_off_t offset, size_t len,
+ enum tdb_lock_flags flags)
+{
+ int count = 1000;
+
+ while (count--) {
+ struct timeval tv;
+ int ret;
+
+ ret = tdb_brlock(tdb, rw_type, offset, len, flags);
+ if (ret == 0) {
+ return 0;
+ }
+ if (errno != EDEADLK) {
+ break;
+ }
+ /* sleep for as short a time as we can - more portable than usleep() */
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ select(0, NULL, NULL, NULL, &tv);
+ }
+ return -1;
+}
+
+/*
+ upgrade a read lock to a write lock.
*/
int tdb_allrecord_upgrade(struct tdb_context *tdb)
{
- int count = 1000;
+ int ret;
if (tdb->allrecord_lock.count != 1) {
TDB_LOG((tdb, TDB_DEBUG_ERROR,
@@ -220,21 +248,12 @@ int tdb_allrecord_upgrade(struct tdb_context *tdb)
return -1;
}
- while (count--) {
- struct timeval tv;
- if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
- TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) {
- tdb->allrecord_lock.ltype = F_WRLCK;
- tdb->allrecord_lock.off = 0;
- return 0;
- }
- if (errno != EDEADLK) {
- break;
- }
- /* sleep for as short a time as we can - more portable than usleep() */
- tv.tv_sec = 0;
- tv.tv_usec = 1;
- select(0, NULL, NULL, NULL, &tv);
+ ret = tdb_brlock_retry(tdb, F_WRLCK, FREELIST_TOP, 0,
+ TDB_LOCK_WAIT|TDB_LOCK_PROBE);
+ if (ret == 0) {
+ tdb->allrecord_lock.ltype = F_WRLCK;
+ tdb->allrecord_lock.off = 0;
+ return 0;
}
TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n"));
return -1;