Thread
-
Re: On file locking
Giles Lean <giles@nemeton.com.au> — 2003-02-03T08:19:39Z
Tom Lane wrote: > On HPUX 10.20, flock doesn't seem to exist (hasn't got a man page nor > any mention in /usr/include). Correct. Still isn't there in later releases. > lockf says > > All locks for a process are released upon > the first close of the file, even if the process still has the file > opened, and all locks held by a process are released when the process > terminates. > > and > > When a file descriptor is closed, all locks on the file from the > calling process are deleted, even if other file descriptors for that > file (obtained through dup() or open(), for example) still exist. > > which seems to imply (but doesn't actually say) that HPUX keeps track of > exactly which process took out the lock, even if the file is held open > by multiple processes. Having done some testing today, I now understand what the standards are trying to say when they talk about locks being "inherited". Or at least I think I understand: standards are tricky, locking is subtle, and I'm prepared to be corrected if I'm wrong! All of these lock functions succeed when the same process asks for a lock that it already has. That is: fcntl(fd, ...); fcntl(fd, ...); /* success -- no error returned */ For flock() only, the lock is inherited by a child process along with the file descriptor so the child can re-issue the flock() call and that will pass, too: flock(fd, ...); pid = fork(); if (pid == 0) flock(fd, ...); /* success -- no error returned */ For fcntl() and lockf() the locks are not inherited, and the call in a child fails: fcntl(fd, ...); pid = fork(); if (pid == 0) fcntl(fd, ...); /* will fail and return -1 */ In no case does just closing the file descriptor in the child lose the parent's lock. I rationalise this as follows: 1. flock() is using a "last close" semantic, so closing the file descriptor is documented not to lose the lock 2. lockf() and fcntl() use a "first close", but because the locks are not inherited by the child process the child can't unlock them > This all doesn't look good for using file locks in the way I had in > mind :-( ... but considering that all these man pages seem pretty vague, > maybe some direct experimentation is called for. I conjecture that Tom was looking for a facility to lock a file and have it stay locked if the postmaster or any child process was still running. flock() fits the bill, but it's not portable everywhere. One additional warning: this stuff *is* potentially filesystem dependent, per the source code I looked at, which would call filesystem specific routines. I tested with HP-UX 11.00 (VxFS), NetBSD (FFS) and Linux (ext3). I've put the rough and ready test code up for FTP, if anyone wants to check my working: ftp://ftp.nemeton.com.au/pub/pgsql/ Limitations in the testing: I only used whole file locking (no byte ranges) and didn't prove that a lock taken by flock() is still held after a child calls close() as it is documented to be. Regards, Giles -
Re: On file locking
Antti Haapala <antti.haapala@iki.fi> — 2003-02-03T12:10:49Z
> All of these lock functions succeed when the same process asks for a > lock that it already has. That is: > > fcntl(fd, ...); > fcntl(fd, ...); /* success -- no error returned */ > > For flock() only, the lock is inherited by a child process along > with the file descriptor so the child can re-issue the flock() > call and that will pass, too: > > flock(fd, ...); > pid = fork(); > if (pid == 0) > flock(fd, ...); /* success -- no error returned */ True... > For fcntl() and lockf() the locks are not inherited, and the > call in a child fails: > > fcntl(fd, ...); > pid = fork(); > if (pid == 0) > fcntl(fd, ...); /* will fail and return -1 */ > > In no case does just closing the file descriptor in the child lose > the parent's lock. I rationalise this as follows: > > 1. flock() is using a "last close" semantic, so closing the file > descriptor is documented not to lose the lock Yep. > 2. lockf() and fcntl() use a "first close", but because the locks > are not inherited by the child process the child can't unlock > them And at least old linux system call manuals seems to reflect this (incorrectly) when they state that file locks are not inherited (should be "record locks obtained by fcntl"). > One additional warning: this stuff *is* potentially filesystem > dependent, per the source code I looked at, which would call > filesystem specific routines. > > I only used whole file locking (no byte ranges) and didn't prove that > a lock taken by flock() is still held after a child calls close() as > it is documented to be. I tested this on Linux 2.4.x ext2 fs and it seems to follow the spec exactly. If child is forked and it closes the file, parent still has the lock until it's killed or it has also closed the file. What about having two different lock files: one that would indicate that there are some child processes still running and another which would indicate that there's postmaster's parent process running? - Using flock and fcntl semantics respectively (or flock semantics with children immediately closing their fds). And of course locking is file system dependant, just think NFS on linux where virtually no locking semantics actually work :) -- Antti Haapala