Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to lock and unlock pid file with "fcntl()"

Tags:

c

linux

fcntl

I make a reseach on the net and even on the stackoverflow inorder to find an example of using fcntl() to lock and unlock pid file "/var/run/myapp.pid" but I did not find a clear example for that.

Could you point me to an example using fcntl() to lock and unlock pid file?

The lock should not be blocked (if the file is alredy locked)

like image 333
MOHAMED Avatar asked Oct 21 '22 08:10

MOHAMED


1 Answers

As you tagged Linux, verbatim form man lockf (emphasis by me):

On Linux, lockf() is just an interface on top of fcntl(2) locking. Many other systems implement lockf() in this way, but note that POSIX.1-2001 leaves the relationship between lockf() and fcntl(2) locks unspecified. A portable application should probably avoid mixing calls to these interfaces.

So looking up the current glibc sources (eglibc-2.11.3/io/lockf.c) a possible usage of fcntl() to implement locking looks like this:

/* Copyright (C) 1994,1996,1997,1998,2000,2003 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

/* lockf is a simplified interface to fcntl's locking facilities.  */

int
lockf (int fd, int cmd, off_t len)
{
  struct flock fl;

  memset ((char *) &fl, '\0', sizeof (fl));

  /* lockf is always relative to the current file position.  */
  fl.l_whence = SEEK_CUR;
  fl.l_start = 0;
  fl.l_len = len;

  switch (cmd)
    {
    case F_TEST:
      /* Test the lock: return 0 if FD is unlocked or locked by this process;
         return -1, set errno to EACCES, if another process holds the lock.  */
      fl.l_type = F_RDLCK;
      if (__fcntl (fd, F_GETLK, &fl) < 0)
        return -1;
      if (fl.l_type == F_UNLCK || fl.l_pid == __getpid ())
        return 0;
      __set_errno (EACCES);
      return -1;

    case F_ULOCK:
      fl.l_type = F_UNLCK;
      cmd = F_SETLK;
      break;
    case F_LOCK:
      fl.l_type = F_WRLCK;
      cmd = F_SETLKW;
      break;
    case F_TLOCK:
      fl.l_type = F_WRLCK;
      cmd = F_SETLK;
      break;

    default:
      __set_errno (EINVAL);
      return -1;
    }

  /* lockf() is a cancellation point but so is fcntl() if F_SETLKW is
     used.  Therefore we don't have to care about cancellation here,
     the fcntl() function will take care of it.  */
  return __fcntl (fd, cmd, &fl);
}

A few mods are necessary to firstly make this compile:

  • replace __fcntl with fcntl
  • replace __set_errno(<errno-define>) with errno = <errno-define>

.. and secondly to have it become async-signal-save:

  • replace the call to memset() with appropriate assigments to the struct fcntl variable.
like image 172
alk Avatar answered Nov 01 '22 11:11

alk