7

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)

MOHAMED
  • 41,599
  • 58
  • 163
  • 268

1 Answers1

5

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.
alk
  • 69,737
  • 10
  • 105
  • 255
  • So If I develop my own `lockf()` function, for example its name will be `async_lockf()`. And then I copy in this function the content of the above function and I make the changes you specified. then the new function `async_lockf()` will be a async-signal-save function and then I can use it in the sigaction handler. is it true ? – MOHAMED Jun 07 '13 at 17:07
  • 1
    for the `memset()`: I will change it to: `struct flock fl = {0}` – MOHAMED Jun 07 '13 at 17:08
  • @MOHAMED: It seems so, yes. But I'd rather refrain from calling it something like `*lockf*` as it does not really refer to `lockf()` but just mimiks it's behaviour. However: You are aware that this is code is GPLed, aren't you? – alk Jun 07 '13 at 17:11
  • No problem for the GPL. I m developing an open source project (GPL) too. and the copyright will be kept – MOHAMED Jun 07 '13 at 17:13
  • So finally we come with a solution for the unlock file with a sync-signal-save inorder to use it in the sigaction handler. Thank you very much for your support. this could be the final answer of my first question – MOHAMED Jun 07 '13 at 17:17
  • @MOHAMED: As a final note: Use this for locking **and** unlocking. Do not mix it up with calls to `flock()`. – alk Jun 07 '13 at 17:28
  • To let the following generations of readers understand to which "first question" *MOHAMED* is referring: http://stackoverflow.com/questions/16967365/how-to-make-a-function-async-signal-save – alk Jun 07 '13 at 17:31
  • yes indeed. thank you very much for the remark. I added this answer to this [topic](http://stackoverflow.com/questions/16979059/use-flock-in-the-sigaction-handler) too – MOHAMED Jun 07 '13 at 17:31
  • in `case F_TEST:`, `fl.l_type = F_RDLCK;` should be `fl.l_type = F_WRLCK;` right? otherwise it will detect read locks only. exclusive lock, `F_WRLCK`, will match/conflict with both types of locks. – Anubis May 05 '15 at 06:53