On Wed, 11 Jan 2006, Payton Swick wrote:

> Would this be correct usage of the file, then?
>
>   def pid
>      dpid = nil
>      File.open(pid_file, File::RDONLY) { |file| dpid = file.gets.chomp if 
> file.flock(File::LOCK_SH|File::LOCK_NB); file.flock(File::LOCK_UN) } if 
> pid_exists?
>      dpid.to_i
>    end
>
>
>    def save_pid
>      File.open(pid_file, File::CREAT|File::EXCL|File::WRONLY) { |file| 
> file.puts $$ if file.flock(File::LOCK_EX); file.flock(File::LOCK_UN) }
>    end

more or less.  it can still get slippery though.  consider:

   def pid
     dpid = nil
     File.open(pid_file, File::RDONLY) { |file| dpid = file.gets.chomp if file.flock(File::LOCK_SH|File::LOCK_NB); file.flock(File::LOCK_UN) } if pid_exists?
     dpid.to_i
   end


       - if the file does not exists this returns nil.to_i, which is 0

       - races still exist:

           0) process a: reader opens existing pidfile

           1) process b: removes pidfile

           2) process a: read lock obtained, pid read

         this works because:

           harp:~ > irb
           irb(main):001:0> open('pid','w'){|f| f.write Process::pid}
           => 4
           irb(main):002:0> f = open 'pid'
           => #<File:pid>
           irb(main):003:0> File::unlink 'pid'
           => 1
           irb(main):004:0> File::exists? 'pid'
           => false
           irb(main):005:0> f.flock File::LOCK_SH|File::LOCK_NB
           => 0
           irb(main):006:0> f.read
           => "4000"

         i think this can be solved by only removing the file while holding a
         write lock.


   def save_pid
     File.open(pid_file, File::CREAT|File::EXCL|File::WRONLY) do |file|
       file.puts $$ if file.flock(File::LOCK_EX); file.flock(File::LOCK_UN)
     end
   end

         - on some filesystems File::EXCL does not work.  on those systems two
           process can succeed in opening the file for writing, waiting for the
           lock, and then writing the pid with the second clobbering the first.
           the open man page details this behaviour.  the only solution is to
           use an operation which atomically creates a file.  the only one i
           know of is 'link'.  i don't think this is worth dealing with though
           since /var/run is probably on a fs for which File::EXCL works...

cheers.

-a
-- 
strong and healthy, who thinks of sickness until it strikes like lightning?
preoccupied with the world, who thinks of death, until it arrives like
thunder?  -- milarepa