* lib/tempfile.rb: Make this libary thread safe.
* lib/tempfile.rb: Do not pick a name which was once used and is still scheduled for removal. * lib/tempfile.rb: A lock file need not and must not be scheduled for removal. * lib/tempfile.rb: Compare Max_try with the number of mkdir failures instead of the suffix counter. * lib/tempfile.rb: Overall cleanup and add some important notices. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3051 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
e6251100cc
commit
34413718ac
15
ChangeLog
15
ChangeLog
@ -1,3 +1,18 @@
|
|||||||
|
Mon Nov 18 02:13:36 2002 Akinori MUSHA <knu@iDaemons.org>
|
||||||
|
|
||||||
|
* lib/tempfile.rb: Make this libary thread safe.
|
||||||
|
|
||||||
|
* lib/tempfile.rb: Do not pick a name which was once used and is
|
||||||
|
still scheduled for removal.
|
||||||
|
|
||||||
|
* lib/tempfile.rb: A lock file need not and must not be scheduled
|
||||||
|
for removal.
|
||||||
|
|
||||||
|
* lib/tempfile.rb: Compare Max_try with the number of mkdir
|
||||||
|
failures instead of the suffix counter.
|
||||||
|
|
||||||
|
* lib/tempfile.rb: Overall cleanup and add some important notices.
|
||||||
|
|
||||||
Sun Nov 17 22:57:31 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net>
|
Sun Nov 17 22:57:31 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net>
|
||||||
|
|
||||||
* parse.y (dsym): garbage returned. (ruby-bugs-ja:PR#358)
|
* parse.y (dsym): garbage returned. (ruby-bugs-ja:PR#358)
|
||||||
|
@ -4,28 +4,37 @@
|
|||||||
# The class for temporary files.
|
# The class for temporary files.
|
||||||
# o creates a temporary file, which name is "basename.pid.n" with mode "w+".
|
# o creates a temporary file, which name is "basename.pid.n" with mode "w+".
|
||||||
# o Tempfile objects can be used like IO object.
|
# o Tempfile objects can be used like IO object.
|
||||||
# o with tempfile.close(true) created temporary files are removed.
|
# o the temporary directory is determined by ENV['TMPDIR'], ENV['TMP'],
|
||||||
# o created files are also removed on script termination.
|
# ENV['TEMP'] and /tmp, in the order named.
|
||||||
|
# o when $SAFE > 0, you should specify a directory via the second argument
|
||||||
|
# of Tempfile::new(), or it will end up finding an ENV value tainted and
|
||||||
|
# pick /tmp. In case you don't have it, an exception will be raised.
|
||||||
|
# o tempfile.close(true) gets the temporary file removed immediately.
|
||||||
|
# o otherwise, the removal is delayed until the object is finalized.
|
||||||
# o with Tempfile#open, you can reopen the temporary file.
|
# o with Tempfile#open, you can reopen the temporary file.
|
||||||
# o file mode of the temporary files are 0600.
|
# o file mode of the temporary files is 0600.
|
||||||
|
# o this library is (considered to be) thread safe.
|
||||||
|
|
||||||
require 'delegate'
|
require 'delegate'
|
||||||
|
|
||||||
class Tempfile < SimpleDelegator
|
class Tempfile < SimpleDelegator
|
||||||
Max_try = 10
|
Max_try = 10
|
||||||
|
@@cleanlist = []
|
||||||
|
|
||||||
def Tempfile.callback(path, data)
|
def Tempfile.callback(data)
|
||||||
pid = $$
|
pid = $$
|
||||||
lambda{
|
lambda{
|
||||||
if pid == $$
|
if pid == $$
|
||||||
|
path, tmpfile, cleanlist = *data
|
||||||
|
|
||||||
print "removing ", path, "..." if $DEBUG
|
print "removing ", path, "..." if $DEBUG
|
||||||
data[0].close if data[0]
|
|
||||||
if File.exist?(path)
|
tmpfile.close if tmpfile
|
||||||
File.unlink(path)
|
|
||||||
end
|
# keep this order for thread safeness
|
||||||
if File.exist?(path + '.lock')
|
File.unlink(path) if File.exist?(path)
|
||||||
Dir.rmdir(path + '.lock')
|
cleanlist.delete(path) if cleanlist
|
||||||
end
|
|
||||||
print "done\n" if $DEBUG
|
print "done\n" if $DEBUG
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
@ -35,30 +44,44 @@ class Tempfile < SimpleDelegator
|
|||||||
if $SAFE > 0 and tmpdir.tainted?
|
if $SAFE > 0 and tmpdir.tainted?
|
||||||
tmpdir = '/tmp'
|
tmpdir = '/tmp'
|
||||||
end
|
end
|
||||||
n = 0
|
|
||||||
while true
|
lock = nil
|
||||||
|
n = failure = 0
|
||||||
|
|
||||||
|
begin
|
||||||
|
Thread.critical = true
|
||||||
|
|
||||||
begin
|
begin
|
||||||
tmpname = sprintf('%s/%s%d.%d', tmpdir, basename, $$, n)
|
tmpname = sprintf('%s/%s%d.%d', tmpdir, basename, $$, n)
|
||||||
lock = tmpname + '.lock'
|
lock = tmpname + '.lock'
|
||||||
unless File.exist?(tmpname) or File.exist?(lock)
|
n += 1
|
||||||
Dir.mkdir(lock)
|
end while @@cleanlist.include?(tmpname) or
|
||||||
break
|
File.exist?(lock) or File.exist?(tmpname)
|
||||||
end
|
|
||||||
rescue
|
Dir.mkdir(lock)
|
||||||
raise "cannot generate tempfile `%s'" % tmpname if n >= Max_try
|
rescue
|
||||||
#sleep(1)
|
failure += 1
|
||||||
end
|
retry if failure < Max_try
|
||||||
n += 1
|
raise "cannot generate tempfile `%s'" % tmpname
|
||||||
|
ensure
|
||||||
|
Thread.critical = false
|
||||||
end
|
end
|
||||||
|
|
||||||
@protect = []
|
@data = [tmpname]
|
||||||
@clean_files = Tempfile.callback(tmpname, @protect)
|
@clean_proc = Tempfile.callback(@data)
|
||||||
ObjectSpace.define_finalizer(self, @clean_files)
|
ObjectSpace.define_finalizer(self, @clean_proc)
|
||||||
|
|
||||||
@tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
|
@tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
|
||||||
@protect[0] = @tmpfile
|
|
||||||
@tmpname = tmpname
|
@tmpname = tmpname
|
||||||
|
@@cleanlist << @tmpname
|
||||||
|
@data[1] = @tmpfile
|
||||||
|
@data[2] = @@cleanlist
|
||||||
|
|
||||||
super(@tmpfile)
|
super(@tmpfile)
|
||||||
|
|
||||||
|
# Now we have all the File/IO methods defined, you must not
|
||||||
|
# carelessly put bare puts(), etc. after this.
|
||||||
|
|
||||||
Dir.rmdir(lock)
|
Dir.rmdir(lock)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -69,15 +92,15 @@ class Tempfile < SimpleDelegator
|
|||||||
def open
|
def open
|
||||||
@tmpfile.close if @tmpfile
|
@tmpfile.close if @tmpfile
|
||||||
@tmpfile = File.open(@tmpname, 'r+')
|
@tmpfile = File.open(@tmpname, 'r+')
|
||||||
@protect[0] = @tmpfile
|
@data[1] = @tmpfile
|
||||||
__setobj__(@tmpfile)
|
__setobj__(@tmpfile)
|
||||||
end
|
end
|
||||||
|
|
||||||
def close(real=false)
|
def close(real=false)
|
||||||
@tmpfile.close if @tmpfile
|
@tmpfile.close if @tmpfile
|
||||||
@protect[0] = @tmpfile = nil
|
@data[1] = @tmpfile = nil
|
||||||
if real
|
if real
|
||||||
@clean_files.call
|
@clean_proc.call
|
||||||
ObjectSpace.undefine_finalizer(self)
|
ObjectSpace.undefine_finalizer(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user