File-Lock-ParentLock

 view release on metacpan or  search on metacpan

lib/File/Lock/ParentLock.pm  view on Meta::CPAN

    $pid||=$$;
    return not (&_lock_status($lockfile,$pid) & _FORBIDDEN_BIT);
}

sub parentlock_is_locked {
    my ($lockfile,$pid) = @_;
    $pid||=$$;
    carp "parentlock_is_locked and is_locked method are deprecated! Use (parentlock_)is_locked_by_us!";
    return &_lock_status($lockfile,$pid) & _PERMITTED_LOCKED_BIT;
}

sub parentlock_is_locked_by_us {
    my ($lockfile,$pid) = @_;
    $pid||=$$;
    return &_lock_status($lockfile,$pid) & _PERMITTED_LOCKED_BIT;
}

sub parentlock_is_locked_by_others {
    my ($lockfile,$pid) = @_;
    $pid||=$$;
    return &_lock_status($lockfile,$pid) == FORBIDDEN_LOCKED_BY_OTHERS;
}

sub _lock_status {
    my ($lockfile,$pid) = @_;
    $pid||=$$;
    my %parentmap;
    my %pidmap;
    my $t = new Proc::ProcessTable( 'enable_ttys' => 0 );

    foreach my $p (@{$t->table}) {
	my $pid=$p->{'pid'};
	$parentmap{$pid}=$p->{'ppid'};
	$pidmap{$pid}=1;
    }

    return PERMITTED_NOT_LOCKED_NO_LOCK_FILE if (! -e $lockfile);
    return FORBIDDEN_NOT_LOCKED_DIR_AT_LOCK_FILE_PATH if ( -d $lockfile);

    my $fh;
    if (!open($fh, '<', $lockfile)) {
	# lock file can't be opened.
	warn "can't open lock file $lockfile: $!\n";
	return FORBIDDEN_LOCKED_ACCESS_ERROR;
    } else {
	my $oldpid=<$fh>;
	close ($fh) or warn "can't close lock file $lockfile: $!";
	unless ($oldpid) {
	    warn "$lockfile does not have a pid";
	    return PERMITTED_NOT_LOCKED_INVALID_LOCK_FILE;
	}
	chomp $oldpid;
	if ($oldpid<=0) {
	    warn "$lockfile: invalid pid value $oldpid";
	    return PERMITTED_NOT_LOCKED_INVALID_LOCK_FILE;
	}

	return PERMITTED_LOCKED_BY_US if ($oldpid==$pid);

	if ($pidmap{$oldpid}) {
	    # old pid still alive;
	    my $intermedpid=$pid;
	    my $counter=0;
	    my $counter_threshhold=70000;
	    while ($intermedpid and $counter++ <$counter_threshhold) {
		if ($intermedpid==$oldpid) {
		    return PERMITTED_LOCKED_BY_PARENT;
		}
		$intermedpid=$parentmap{$intermedpid};
	    }
	    die "threshhold reached for $oldpid" if $counter >=$counter_threshhold;
	    # lock is valid but we are not born from parent
	    return FORBIDDEN_LOCKED_BY_OTHERS;
	}
	# lock file's pid is dead.
	return PERMITTED_NOT_LOCKED_STALE_LOCK_FILE;
    }
}

sub _write_lock {
    my ($lockfile, $pid)=@_;
    # try to remove it if it exists.
    unlink $lockfile;

    sysopen(FH, $lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644)
	or die "can't open lock file $lockfile: $!";
    syswrite(FH, "$pid");
    close (FH) or die "can't close lock file $lockfile: $!";
}


__END__



=head1	NAME

File::Lock::ParentLock - share lock among child processes of given pid.

=head1	SYNOPSIS

my $locker= File::Lock::ParentLock->new(
	-lockfile=>$lockfile,
	-pid=>$pid,
    );

die $locker->status_string() if !$locker->lock();
...
die $locker->status_string() if !$locker->unlock();


=head1	DESCRIPTION

File::Lock::ParentLock is useful for shell scripting where there are 
lots of nested script calls and we want to share a lock through the
parent - child relationship.

=head1	METHODS

=over



( run in 1.862 second using v1.01-cache-2.11-cpan-14f38c9f855 )