--- /org/python/core/PyFile.java Tue Dec 5 23:58:34 2006 +++ PyFile.java Wed Jan 17 11:43:00 2007 @@ -1,6 +1,9 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.core; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import java.io.*; // To do: @@ -1482,6 +1485,7 @@ this.file = new TextWrapper(file); else this.file = file; + register(this); } public PyFile(java.io.InputStream istream, java.io.OutputStream ostream, @@ -1839,11 +1843,10 @@ } final void file_close() { - try { - file.close(); - } catch (java.io.IOException e) { - throw Py.IOError(e); - } + if(closer != null){ + closer.file_close(); + closer = null; + } closed = true; file = new FileWrapper(); } @@ -1926,4 +1929,80 @@ public boolean getClosed() { return closed; } + + protected void finalize() throws Throwable{ + super.finalize(); + if(closer != null){ + closer.file_close(); + } + } + + /** + * Moving the code here allows us to close PyFiles regardless of + * their finalization status. Using WeakReferences and their ilk + * may run the chance of slipping a Closer off on a finalization queue + * where we may not get a chance to close them down from the shutdown + * hook. There does not appear to be any guarantee that finalization + * will run ever, this includes shutdown time. + */ + static class Closer{ + FileWrapper file; + Closer(PyFile pf){ + file = pf.file; + } + + void file_close() { + synchronized(closers){ + if(!closers.remove(this)) + return; + } + _file_close(); + } + + public void _file_close(){ + if(file == null) return; + try { + file.close(); + } catch (java.io.IOException e) { + throw Py.IOError(e); + } finally{ file = null; } + } + } + + + Closer closer; + static List closers; + static{ + closers = new LinkedList(); + try{ + Runtime.getRuntime().addShutdownHook(new PyFileCloser()); + } catch(SecurityException e){ + System.err.println("Can't register PyFile closing hook"); + } + } + + static void register(PyFile file){ + file.closer = new Closer(file); + synchronized(closers){ + closers.add(file.closer); + } + } + + static class PyFileCloser extends Thread{ + public void run(){ + Closer closer; + while(true){ + synchronized(closers){ + if(closers.size() != 0) + closer = (Closer)closers.remove(0); + else break; + } + try{ + closer._file_close(); + } catch(PyException e){} + } + } + } + + }