Aucbvax.3062
fa.unix-wizards
utzoo!decvax!ucbvax!unix-wizards
Thu Sep 10 15:48:41 1981
Resource locking
>From dcrocker@udel Thu Sep 10 15:40:53 1981
   Around the middle of August, there was a discussion in Unix-
Wizards about providing a safe locking mechanism in Unix, given
the absence of a built-in system feature, such as the suggested
"lock" driver or the addition to the open(2) call, done by Greep
at Rand.  Or having ioctl(2) work on ANY filename, rather than
only working on terminals.  (Others no doubt also have hacked
something to accomplish this.)

   It was suggested that link(2) was an atomic action and
constituted a valid test-and-set resource.  Then Dave Yost
pointed out one of those little items of reality that so often
imposes itself onto Unix; namely, the process setting the lock
may inconsiderately go away without cleaning up.  Using timeouts
is a way of remedying this problem, but only probabilistically.
There is always a (reasonable) chance that the original owner
really is using the resource for a long time; forcing them to do
periodic resets on the timer is a pain.

   It was suggested storing the process id into the lock file
and a requestor can then find out if the holder is still around.
If they are not, then the problem is how to clean up the lock
file without two processes stepping on each other.  It was
asserted that you would always have a finite chance that two
processes would write on the lockfile.  The question was left at
that.

   I believe that I have an algorithm which solves that problem
and would very much like to solicit comments on it.  I have a
strong need for a valid locking mechanism which works on vanilla
Unix.

   The principle is simply to do test-set-test.  There is
provision for collision handling, by using a simple back-off
scheme.

   Try to link.  If you do, write your pid into the file.  Then
read the file and see if the pid is yours.

   If the link fails, check the lockfile.  If it is empty,
assume someone else is trying to set it.  Give them a while to
make the file non-zero (e.g., up to a minute).  Then signal the
process that is listed.

   The link(2) call is not strictly necessary for this
mechanism.  However, I suspect that it will reduce collisions
from what would occur if creat(2) were the basic operation.

   The following is a more cryptic listing of the full
algorithm:


dolock:
   link (basefile, lockfile)     /* basefile always exists */

   if (no basefile)              /* well, it is supposed to */
   {   create basefile
       if (create error)
           RETURN (SYS ERROR)
       goto dolock
   }

   if (successful link)          /* implies resource was free */
       write mypid into lockfile /* try to publicize new owner */

testlock:

   if (lockfile owner not my uid)
       RETURN (SYS ERROR)

   up to 6 iterations            /* keep waiting for a pid to be stored */
   {   read lockpid from lockfile

       if (non-zero read)        /* at least one pid got stored */
       {   if (lockpid is mine)
               RETURN (LOCK OK)

           switch (signal lockpid)
           {   case  no process: /* they died badly */
                     goto badlock

               case  other error:
                     RETURN (SYS ERROR)

               case  ok:
                     RETURN (LOCK DENY)
           }
       }
       sleep (10)                /* zero read => wait for writing */
   }

badlock:
   remove lockfile
   goto dolock

-----------------------------------------------------------------
gopher://quux.org/ conversion by John Goerzen <[email protected]>
of http://communication.ucsd.edu/A-News/


This Usenet Oldnews Archive
article may be copied and distributed freely, provided:

1. There is no money collected for the text(s) of the articles.

2. The following notice remains appended to each copy:

The Usenet Oldnews Archive: Compilation Copyright (C) 1981, 1996
Bruce Jones, Henry Spencer, David Wiseman.