Skip Menu |

This queue is for tickets about the File-NFSLock CPAN distribution.

Report information
The Basics
Id: 48102
Status: resolved
Worked: 3 hours (180 min)
Priority: 0/
Queue: File-NFSLock

People
Owner: Nobody in particular
Requestors: todd.foggoa [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: 1.26



Subject: NFSLock bug when using fork()
Date: Wed, 22 Jul 2009 21:09:30 -0400
To: bug-File-NFSLock [...] rt.cpan.org
From: Todd Foggoa <todd.foggoa [...] gmail.com>
If the parent grabs a lock and then forks a child, the parents lock is incorrectly released when the child exits because there is no check for PID in the DESTORY function. I noticed this problem for exclusive locks, there maybe some more logic required for shared locks. Also, note this still works with the newpid function which, if used, will allow the child to release the lock becuase the "lock_pid" is changed to the child pid in the newpid function. This was seen in the latest 1.20 version of the NFSLock module: Exisiting code: sub DESTROY { shift()->unlock(); } Fixed code: sub DESTROY { my $self = shift; # maybe some extra checking is needed here for shared locks ? if ($self->{lock_pid} == $$) { $self->unlock(); } } Here is a rough code example highlighting the problem: $lock = File::NFSLock->new("lockfile", LOCK_EX, 30, 60)); # some processing $child = fork(); if ($child) { # parent # some processing wait(); } else { # child # some processing exit 0; # <<<<<<< lock is wrongly released here } # some processing $lock->unlock(); Thanks, -Todd
RT-Send-CC: bbb [...] cpan.org, rhandom [...] cpan.org
On Wed Jul 22 21:09:59 2009, todd.foggoa@gmail.com wrote: Show quoted text
> If the parent grabs a lock and then forks a child, the parents lock is > incorrectly released when the child exits because there is no check > for PID in the DESTORY function. I noticed this problem for exclusive > locks, there maybe some more logic required for shared locks. Also, > note this still works with the newpid function which, if used, will > allow the child to release the lock becuase the "lock_pid" is changed > to the child pid in the newpid function.
Todd, Under Linux, if you flock() and then fork(), then BOTH the child and the parent still have the lock enforced. This can already pose problems if both processes think they are exclusively safe to work on a resource. But I've seen under Solaris, and some other OS's, where only the parent retains the lock. I was hoping to mimic the behavior of Linux by retaining the lock within the child. That way, a process can acquire the NFSLock, and the fork(), and then allow the child to do processing like a daemon, while the parent just _exit(0) to background. But if the child doesn't release the lock when it was destroyed, than it would leave all its crusty rand files dangling around. Maybe I'll just claim in the CAVEATS that it is undefined behavior of you fork() while a lock object is still enforced so people don't try to do what you are doing???
Maybe a better solution would be to force the newpid() method to always mimic the Linux flock() behavior by enforcing the lock between BOTH parent and child instead of migrating the lock from parent to child. #1 For shared locks, this can be achieved fairly easily. Just create a new lock_line for the child process and add that to the shared lock list. #2 For exclusive locks, this can be achieved by upgrading the exclusive lock to a shared lock and then adding the new child lock_line to the lock list. BUT this lock_type must only appear to be "shared" from the internal object's point of view. (The $SHARE_BIT must not be set on the actual lock file, otherwise external shared lock attempts can falsely be acquired, which should never happen while an "exclusive" lock is still being held.)
Both suggestions #1 and #2 have been implemented in version 1.26.
Using $lock_obj->fork() instead of CORE::fork() allows the acquired lock to be shared between both processes safely.