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 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.