15.01.2015 Views

4th International Conference on Principles and Practices ... - MADOC

4th International Conference on Principles and Practices ... - MADOC

4th International Conference on Principles and Practices ... - MADOC

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

01 public void sendFile(ResourceNode parent,<br />

02 File f) {<br />

03 try {<br />

04 ManagedSocket s = new //...<br />

05 FileInputStream in =<br />

06 new ManagedFileInputStream(f,g);<br />

07 ManagedOutputStream out =<br />

08 s.getOutputStream();<br />

09 byte[] buf = new byte[4096];<br />

10 int len;<br />

11 while ((len = in.read(buf)) >= 0) {<br />

12 out.write(buf, 0, len);<br />

13 }<br />

14 } catch (IOExcepti<strong>on</strong> exc) {}<br />

15 parent.release();<br />

16 }<br />

Figure 2-12. A “leaky” method<br />

2.5 Automatic Resource Cleanup<br />

When properly used, Furm opens up new possibilities for resource<br />

auditing. Furm provides a WatchDog class for m<strong>on</strong>itoring threads<br />

for proper resource cleanup. A WatchDog is given a thread to<br />

guard, <strong>and</strong> a reference to the root of the resource tree (or subtree)<br />

being used by that thread. Whenever that thread dies, the<br />

WatchDog can take some acti<strong>on</strong> <strong>on</strong> any resources ab<strong>and</strong><strong>on</strong>ed by<br />

that thread. This can be used as a safeguard to prevent resource<br />

leaks at runtime. The WatchDog can also be used as a resource<br />

profiler. If resource leaks are suspected or known to exist, every<br />

thread in a program can be assigned a WatchDog for tracing<br />

purposes. As threads die, any resources they leave open can be<br />

inspected. Informati<strong>on</strong> about those resources can aid in tracking<br />

down the leak.<br />

There are two ways to c<strong>on</strong>trol what acti<strong>on</strong> will take place when a<br />

thread dies. The first is to provide a ThreadListener. When a<br />

WatchDog observes that its thread has died, it will call the<br />

threadDied() method <strong>on</strong> the ThreadListener, much the way a<br />

ResourceNode calls excepti<strong>on</strong>Thrown() <strong>on</strong> an Excepti<strong>on</strong>Listener.<br />

To specify a ThreadListener, simply pass it to the WatchDog<br />

c<strong>on</strong>structor. The sec<strong>on</strong>d way to c<strong>on</strong>trol what acti<strong>on</strong> the<br />

WatchDog should take is to extend the WatchDog class <strong>and</strong><br />

override its threadDied() method. The WatchDog class itself<br />

implements the ThreadListener interface, <strong>and</strong> so has the<br />

threadDied() method. 5<br />

WatchDog has two WatchLevels. The WatchLevel determines<br />

what forms of thread terminati<strong>on</strong> will be m<strong>on</strong>itored. The two<br />

WatchLevels are excepti<strong>on</strong>al (declared as EXCEPTIONAL_END)<br />

<strong>and</strong> general (declared as ANY_END). If the WatchLevel is<br />

excepti<strong>on</strong>al, then the threadDied() method will <strong>on</strong>ly be called if<br />

the thread dies by throwing an uncaught excepti<strong>on</strong>. If the<br />

WatchLevel is general, then the threadDied() method will be<br />

called regardless of the circumstances of thread terminati<strong>on</strong>.<br />

As an example of how to use the WatchDog class, we present a<br />

small, “leaky” method which uses Furm. This method simply<br />

creates a socket c<strong>on</strong>necti<strong>on</strong> <strong>and</strong> sends a file to the output stream<br />

of the socket. Figure 2-12 c<strong>on</strong>tains its full implementati<strong>on</strong>.<br />

5 This model follows that of the Thread class, which has a<br />

c<strong>on</strong>structor that accepts a Runnable object, but also implements<br />

the Runnable interface.<br />

01 class Examiner implements ThreadListener {<br />

02 private void printRes(ResourceNode res) {<br />

03 Class c = res.getResource().getClass()<br />

04 System.out.println(c.getCan<strong>on</strong>icalName());<br />

05 for (ResourceNode rn : res) {<br />

06 printResource(rn);<br />

07 }<br />

08 }<br />

09 public void threadDied(Thread t,<br />

10 ResourceNode node,<br />

11 Throwable e) {<br />

12 synchr<strong>on</strong>ized(node.getM<strong>on</strong>itor()) {<br />

13 if (!node.isReleased()) {<br />

14 printRes(node);<br />

15 node.release();<br />

16 }<br />

17 }<br />

18 }<br />

19 }<br />

20 // ...<br />

21 new WatchDog(Thread.currentThread(),group,<br />

22 new Examiner(),WatchLevel.ANY_END);<br />

Figure 2-13. Utilizing WatchDog<br />

Notice that the file transfer code is wrapped in a try-catch block<br />

which catches IOExcepti<strong>on</strong> (lines 3-14). The release() call is<br />

made <strong>on</strong> line 15. While this code will work in cases when no<br />

errors occur or when an IOExcepti<strong>on</strong> is thrown, if the File<br />

reference passed into the method is null, a NullPointerExcepti<strong>on</strong><br />

will occur <strong>on</strong> line 6, <strong>and</strong> the release() call will never be made.<br />

The Socket <strong>and</strong> socket output stream will be leaked. The correct<br />

soluti<strong>on</strong> is to add a finally h<strong>and</strong>ler, but here this has not been<br />

d<strong>on</strong>e. If the code were part of a very large project, it may be<br />

reas<strong>on</strong>able to assume that no <strong>on</strong>e has discovered the bug.<br />

Let us assume that the WatchDog class is being used to hunt for a<br />

suspected bug, or that the WatchDog is simply being used as an<br />

additi<strong>on</strong>al safeguard in development code. To this end, the<br />

Examiner class (Figure 2-13) is added. Lines 21 <strong>and</strong> 22 create a<br />

WatchDog to m<strong>on</strong>itor the thread. A WatchDog can be created to<br />

watch any thread. In this case, it is created to m<strong>on</strong>itor the current<br />

thread. The Examiner class used here implements ThreadListener<br />

<strong>and</strong> performs two tasks in the threadDied() callback. First, it<br />

traverses the tree to discover any unreleased resources <strong>and</strong> prints<br />

that informati<strong>on</strong>. Sec<strong>on</strong>d, it releases the tree.<br />

An Examiner object is passed to the WatchDog c<strong>on</strong>structor, <strong>and</strong><br />

the general WatchLevel is specified. When the current thread<br />

dies, whether normally or as the result of an uncaught excepti<strong>on</strong>,<br />

the Examiner object will inspect the thread’s resource tree. This<br />

simple auditing may reveal the problem with the sendFile()<br />

method. The WatchDog class is not a replacement for correct<br />

resource management, but it can make it simpler to track down<br />

cases of incorrect behavior.<br />

One major benefit of the WatchDog class is that its use does not<br />

require watched threads to be aware of its presence. In fact, it is<br />

entirely possible for multiple WatchDogs to watch the same<br />

thread, each oblivious to the others, <strong>and</strong> the thread itself blind to<br />

them all. The main restricti<strong>on</strong> <strong>on</strong> the use of the WatchDog class<br />

is that it requires that any thread m<strong>on</strong>itored by a WatchDog place<br />

its resources in a resource tree. The WatchDog class cannot<br />

m<strong>on</strong>itor resources which are not in a resource tree. Watched<br />

threads can ignore the WatchDogs, but must utilize Furm resource<br />

trees.<br />

121

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!