Make rpm locks reference counted to allow nested locking

- Note that unlike our "normal" refcounts, this counts references to
  the file descriptor itself: an open descriptor is one reference,
  and acquired locks are on top of that.
- This also moves the NULL checks to the external interface, we
  need to NULL-check there anyway so there's no point rechecking
  in internals.
This commit is contained in:
Panu Matilainen 2013-03-11 11:53:13 +02:00
parent 87188275ad
commit 4d0e7f78dc
1 changed files with 24 additions and 6 deletions

View File

@ -17,6 +17,7 @@ struct rpmlock_s {
int openmode;
char *path;
char *descr;
int fdrefs;
};
static rpmlock rpmlock_new(const char *lock_path, const char *descr)
@ -42,6 +43,7 @@ static rpmlock rpmlock_new(const char *lock_path, const char *descr)
if (lock) {
lock->path = xstrdup(lock_path);
lock->descr = xstrdup(descr);
lock->fdrefs = 1;
}
}
return lock;
@ -49,7 +51,7 @@ static rpmlock rpmlock_new(const char *lock_path, const char *descr)
static void rpmlock_free(rpmlock lock)
{
if (lock) {
if (--lock->fdrefs == 0) {
free(lock->path);
free(lock->descr);
(void) close(lock->fd);
@ -60,7 +62,13 @@ static void rpmlock_free(rpmlock lock)
static int rpmlock_acquire(rpmlock lock, int mode)
{
int res = 0;
if (lock && (mode & lock->openmode)) {
if (!(mode & lock->openmode))
return res;
if (lock->fdrefs > 1) {
res = 1;
} else {
struct flock info;
int cmd;
if (mode & RPMLOCK_WAIT)
@ -78,12 +86,19 @@ static int rpmlock_acquire(rpmlock lock, int mode)
if (fcntl(lock->fd, cmd, &info) != -1)
res = 1;
}
lock->fdrefs += res;
return res;
}
static void rpmlock_release(rpmlock lock)
{
if (lock) {
/* if not locked then we must not release */
if (lock->fdrefs <= 1)
return;
if (--lock->fdrefs == 1) {
struct flock info;
info.l_type = F_UNLCK;
info.l_whence = SEEK_SET;
@ -127,6 +142,7 @@ int rpmlockAcquire(rpmlock lock)
void rpmlockRelease(rpmlock lock)
{
if (lock)
rpmlock_release(lock);
}
@ -140,8 +156,10 @@ rpmlock rpmlockNewAcquire(const char *lock_path, const char *descr)
rpmlock rpmlockFree(rpmlock lock)
{
rpmlock_release(lock); /* Not really needed here. */
if (lock) {
rpmlock_release(lock);
rpmlock_free(lock);
}
return NULL;
}