Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where does Ruby keep track of its open file descriptors?

Tags:

What This Question Is Not About

This question is not about how to auto-close a file with File#close or the File#open block syntax. It's a question about where Ruby stores its list of open file descriptors at runtime.

The Actual Question

If you have a program with open descriptors, but you don't have access to the related File or IO object, how can you find a reference to the currently-open file descriptors? Take this example:

filename='/tmp/foo' %x( touch "#{filename}" ) File.open(filename) filehandle = File.open(filename) 

The first File instance is opened, but the reference to the object is not stored in a variable. The second instance is stored in filehandle, where I can easily access it with #inspect or #close.

However, the discarded File object isn't gone; it's just not accessible in any obvious way. Until the object is finalized, Ruby must be keeping track of it somewhere...but where?

like image 288
Todd A. Jacobs Avatar asked Jun 06 '12 20:06

Todd A. Jacobs


People also ask

Where are open file descriptors stored?

On Linux, the set of file descriptors open in a process can be accessed under the path /proc/PID/fd/ , where PID is the process identifier.

What is a file descriptor in Ruby?

A file descriptor is a mapping between an integer & a file name.

What is IO in Ruby?

The IO class is the basis for all input and output in Ruby. An I/O stream may be duplexed (that is, bidirectional), and so may use more than one native operating system stream. Many of the examples in this section use the File class, the only standard subclass of IO. The two classes are closely associated.

What is the syntax to close file in Ruby?

You can create a File object using File. new method for reading, writing, or both, according to the mode string. Finally, you can use File. close method to close that file.


1 Answers

TL; DR

All File and IO objects are stored in ObjectSpace.

Answer

The ObjectSpace class says:

The ObjectSpace module contains a number of routines that interact with the garbage collection facility and allow you to traverse all living objects with an iterator.

How I Tested This

I tested this at the console on Ruby 1.9.3p194.

The test fixture is really simple. The idea is to have two File objects with different object identities, but only one is directly accessible through a variable. The other is "out there somewhere."

# Don't save a reference to the first object. filename='/tmp/foo' File.open(filename) filehandle = File.open(filename) 

I then explored different ways I could interact with the File objects even if I didn't use an explicit object reference. This was surprisingly easy once I knew about ObjectSpace.

# List all open File objects. ObjectSpace.each_object(File) do |f|   puts "%s: %d" % [f.path, f.fileno] unless f.closed? end  # List the "dangling" File object which we didn't store in a variable. ObjectSpace.each_object(File) do |f|   unless f.closed?       printf "%s: %d\n", f.path, f.fileno unless f === filehandle   end end  # Close any dangling File objects. Ignore already-closed files, and leave # the "accessible" object stored in *filehandle* alone. ObjectSpace.each_object(File) {|f| f.close unless f === filehandle rescue nil} 

Conclusion

There may be other ways to do this, but this is the answer I came up with to scratch my own itch. If you know a better way, please post another answer. The world will be a better place for it.

like image 57
Todd A. Jacobs Avatar answered Oct 21 '22 08:10

Todd A. Jacobs