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

1

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)

Persimmon answered 7/6, 2013 at 15:55 Comment(0)
C
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.
Croissant answered 7/6, 2013 at 16:42 Comment(9)
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 ?Persimmon
for the memset(): I will change it to: struct flock fl = {0}Persimmon
@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?Croissant
No problem for the GPL. I m developing an open source project (GPL) too. and the copyright will be keptPersimmon
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 questionPersimmon
@MOHAMED: As a final note: Use this for locking and unlocking. Do not mix it up with calls to flock().Croissant
To let the following generations of readers understand to which "first question" MOHAMED is referring: #16967865Croissant
yes indeed. thank you very much for the remark. I added this answer to this topic tooPersimmon
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.Dhobi

© 2022 - 2024 — McMap. All rights reserved.