简体   繁体   中英

fcntl how to know which process hold lock file?

I'm new with fcntl locking and following this example to create a sample lock in linux using c code: http://www.informit.com/articles/article.aspx?p=23618&seqNum=4

I wonder how can we can print out which process hold the lock file and which process is waiting for lock. I consider using l_pid to figure out the process id which is holding the lock but i'm not sure the right way to do it. What is the best way to print out which process is holding the lock?

As the man 2 fcntl page describes, you can use the F_GETLK to obtain the process ID that has the conflicting lock (if the conflicting lock is a process-associated one). So, for example,

/* Return 0 if descriptor locked exclusively, positive PID if
   a known process holds a conflicting lock, or -1 if the
   descriptor cannot be locked (and errno has the reason).
*/
static pid_t  lock_exclusively(const int fd)
{
    struct flock  lock;
    int           err = 0;

    if (fd == -1) {
        errno = EINVAL;
        return -1;
    }

    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
    if (!fcntl(fd, F_SETLK, &lock))
        return 0;

    /* Remember the cause of the failure */
    err = errno;

    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
    lock.l_pid = 0;
    if (fcntl(fd, F_GETLK, &lock) == 0 && lock.l_pid > 0)
        return lock.l_pid;

    errno = err;
    return -1;
}

Do note that fd must be open for reading and writing. I recommend using open(path, O_RDWR | O_NOCTTY) or open(path, O_WRONLY | O_NOCTTY) . Closing any file descriptor to the same file will release the lock.

Some may say that re-setting the lock memebers before the second fcntl() call is unnecessary, but I'd rather err on the side of caution here.

As to how to report it, I would simply use

int    fd;
pid_t  p;

fd = open(path, O_RDWR | O_NOCTTY);
if (fd == -1) {
    fprintf(stderr, "%s: Cannot open file: %s.\n",
                    path, strerror(errno));
    exit(EXIT_FAILURE);
}

p = lock_exclusively(fd);
if (p < 0) {
    fprintf(stderr, "%s: Cannot lock file: %s.\n",
                    path, strerror(errno));
    exit(EXIT_FAILURE);
} else
if (p > 0) {
    fprintf(stderr, "%s: File is already locked by process %ld.\n",
                    path, (long)p);
    exit(EXIT_FAILURE);
}

/* fd is now open and exclusive-locked. */

The user can always run eg ps -o cmd= -p PID to see what command that is (or you can try reading /proc/PID/cmdline in Linux).

From the example code:

printf ("locking\n");
/* Initialize the flock structure. */
memset (&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
/* Place a write lock on the file. */
fcntl (fd, F_SETLKW, &lock);

printf ("locked; hit Enter to unlock... ");

You need to change the fcntl (fd, F_SETLKW, &lock); to:

if (fcntl (fd, F_SETLK, &lock) == -1) {
  printf ("File is locked by pid %i\n", lock.l_pid);
  return 0;
}

The F_SETLKW command blocks if it cannot get the lock. F_SETLK will return if it cannot get the lock. Really the code should also check errno == EACCESS or errno == EAGAIN after getting the -1 return value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM