34
Subsystems: Improved exception handling for Java (DRAFT) Bart Jacobs, Frank Piessens

Subsystems: Improved exception handling for Java (DRAFT)

  • Upload
    caesar

  • View
    51

  • Download
    0

Embed Size (px)

DESCRIPTION

Subsystems: Improved exception handling for Java (DRAFT). Bart Jacobs, Frank Piessens. Outline. Try-Catch: Problem + Solution Locking: Problem + Solution Cancellation: Problem + Solution Cleaning Up: Problem + Solution. Outline. Try-Catch: Problem + Solution Locking: Problem + Solution - PowerPoint PPT Presentation

Citation preview

Page 1: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems: Improved exception handling for

Java (DRAFT)

Bart Jacobs, Frank Piessens

Page 2: Subsystems: Improved exception handling for Java (DRAFT)

Outline

Try-Catch: Problem + Solution Locking: Problem + Solution Cancellation: Problem + Solution Cleaning Up: Problem + Solution

Page 3: Subsystems: Improved exception handling for Java (DRAFT)

Outline

Try-Catch: Problem + Solution Locking: Problem + Solution Cancellation: Problem + Solution Cleaning Up: Problem + Solution

Page 4: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:A Typical Try-Catch Patternclass Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10];

Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

void removeWidget(Widget w) { … }}

class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } …}

This program is broken!

Why?

Page 5: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:An OutOfMemoryError…class Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10];

Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

void removeWidget(Widget w) { … }}

class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } …}

m.count == 11

m.widgets.length == 10

Page 6: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:An OutOfMemoryError…class Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10];

Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

void removeWidget(Widget w) { … }}

class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } …}

1

2

3

4

m.count == 11

m.widgets.length == 10

Page 7: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:An OutOfMemoryError…class Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10];

Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

void removeWidget(Widget w) { … }}

class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } …}

1

2

3

4

5

m.count == 12

m.widgets.length == 10

Page 8: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:A Typical Try-Catch Patternclass Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10];

Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

void removeWidget(Widget w) { … }}

class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } …}

Page 9: Subsystems: Improved exception handling for Java (DRAFT)

class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } void removeWidget(Widget w) { … }}

Proposed Solution:Re-entering the Owner Subsystem

class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } …}

root subsyste

m

child subsyste

m

Page 10: Subsystems: Improved exception handling for Java (DRAFT)

class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } …}

class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } void removeWidget(Widget w) { … }}

Proposed Solution:Re-entering an Outer Subsystem

Page 11: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems: Basic Operation

class Program { public static void main(String[] args) { Subsystem s = Subsystem.getCurrent(); try { reenter (s) { throw new RuntimeException(); } } catch (Throwable t) { System.out.println(t + “ was caught.”); } }}

Not caught

Page 12: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems: Basic Operationclass Program { public static void main(String[] args) { try { Subsystem s = Subsystem.getCurrent(); try { reenter (s) { throw new RuntimeException(); } } catch (Throwable t) { System.out.println(t + “ caught by inner.”); } } catch (Throwable t) { System.out.println(t + “ caught by outer.”); } }}

Caught by outer

Page 13: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems: Implementationclass Subsystem { static Stack<Subsystem> stack = new Stack<Subsystem>(); static { stack.push(new Subsystem(); } Throwable exception; Subsystem parent; List<Subsystem> children = new ArrayList<Subsystem>(); static Subsystem getCurrent() { return stack.peek(); } static void enterNew() { Subsystem s = new Subsystem(); s.parent = getCurrent(); getCurrent().children.add(s); stack.push(s); } static void reenter(Subsystem s) { s.checkNotFailed(); stack.push(s); } static void exit(Throwable e) { if (e != null) getCurrent().setFailed(e); stack.pop(); getCurrent().checkNotFailed(); } void setFailed(Throwable e) { exception = e; for (Subsystem c : children) c.setFailed(e); } void checkNotFailed() { if (exception != null) throw exception; } static void finish(Throwable e) { getCurrent().parent.children.remove(getCurrent()); exit(e); }}

Expansion [[ try { S } catch (Throwable e) { S’ } ]] = Subsystem.enterNew(); Throwable t = null; try { S } catch (Throwable e) { t = e; } Subsystem.finish(t); if (t != null) { Throwable e = t; S’ }

Expansion [[ reenter (s) { S } ]] = Subsystem.reenter(s); Throwable t = null; try { S } catch (Throwable e) { t = e; } Subsystem.exit(t); if (t != null) { throw t; }

Page 14: Subsystems: Improved exception handling for Java (DRAFT)

Outline

Try-Catch: Problem + Solution Locking: Problem + Solution Cancellation: Problem + Solution Cleaning Up: Problem + Solution

Page 15: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:A Typical Locking Patternclass Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10];

synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

synchronized void removeWidget(Widget w) { … }}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

This program is broken!

Why?

Page 16: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:An OutOfMemoryError…class Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10];

synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

synchronized void removeWidget(Widget w) { … }}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

In thread 1

m.count == 11

m.widgets.length == 10

Page 17: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:An OutOfMemoryError…class Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10];

synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

synchronized void removeWidget(Widget w) { … }}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

In thread 1

In thread 2

m.count == 12

m.widgets.length == 10

Page 18: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems To The Rescueclass WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10];

synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

Page 19: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems To The Rescueclass WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10];

synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

In thread 1

Page 20: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems To The Rescueclass WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10];

synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

In thread 1

In thread 2

Page 21: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems To The Rescueclass WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10];

synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

In thread 1

In thread 2

In main thread

Page 22: Subsystems: Improved exception handling for Java (DRAFT)

Subsystems

When an exception occurs in a subsystem s For safety: New attempts to enter s (or a

descendant) rethrow the exception, and

For liveness: Computations executing in s (or a descendant) in other threads are stopped I.e.: In each thread that is executing in s (or a

descendant), an exception is thrown (using Thread.stop()), which is caught when leaving s

Page 23: Subsystems: Improved exception handling for Java (DRAFT)

Outline

Try-Catch: Problem + Solution Locking: Problem + Solution Cancellation: Problem + Solution Cleaning Up: Problem + Solution

Page 24: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:A Typical Cancellation Patternclass Task { boolean cancel; Thread thread; synchronized void cancel() { cancel = true; if (thread != null) thread.stop(); } synchronized void setThread(Thread t) { thread = t; if (cancel) throw new ThreadDeath(); }}

class Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setThread(Thread.currentThread()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

This program is broken!

Why?

Page 25: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:A ThreadDeath…class Task { boolean cancel; Thread thread; synchronized void cancel() { cancel = true; if (thread != null) thread.stop(); } synchronized void setThread(Thread t) { thread = t; if (cancel) throw new ThreadDeath(); }}

class Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setThread(Thread.currentThread()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

ThreadDeath in thread 1

m.count == 11

m.widgets.length == 10

Page 26: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:A ThreadDeath…class Task { boolean cancel; Thread thread; synchronized void cancel() { cancel = true; if (thread != null) thread.stop(); } synchronized void setThread(Thread t) { thread = t; if (cancel) throw new ThreadDeath(); }}

class Widget { … }class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setThread(Thread.currentThread()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

ThreadDeath in thread 1

m.count == 12

m.widgets.length == 10

In thread 2

Page 27: Subsystems: Improved exception handling for Java (DRAFT)

Proposed Solution:Subsystem Cancellationclass Task { boolean cancel; Subsystem subsystem; synchronized void cancel() { cancel = true; if (subsystem != null) subsystem.cancel(); } synchronized void setSubsystem(Subsystem s) { subsystem = s; if (cancel) throw new ThreadDeath(); }}

class Widget { … }class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setSubsystem(Subsystem.getCurrent()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

Page 28: Subsystems: Improved exception handling for Java (DRAFT)

Proposed Solution:Subsystem Cancellationclass Task { boolean cancel; Subsystem subsystem; synchronized void cancel() { cancel = true; if (subsystem != null) subsystem.cancel(); } synchronized void setSubsystem(Subsystem s) { subsystem = s; if (cancel) throw new ThreadDeath(); }}

class Widget { … }class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } …}

class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setSubsystem(Subsystem.getCurrent()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } …}

(Child subsystem is

cancelled)

ThreadDeath on entry to

child

Page 29: Subsystems: Improved exception handling for Java (DRAFT)

Outline

Try-Catch: Problem + Solution Locking: Problem + Solution Cancellation: Problem + Solution Cleaning Up: Problem + Solution

Page 30: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:A Typical Cleanup Patternclass Widget implements Closeable { WidgetManager m; Widget(WidgetManager m) { this.m = m; } public void close() { m.removeWidget(this); } …}class WidgetManager { int count; Widget[] widgets = new Widget[10];

Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

void removeWidget(Widget w) { … }}

class Program { static Widget allocGreenWidget(WidgetManager m) { Widget w = m.allocWidget(); w.setColor(Color.green); return w; } public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … Widget w = allocGreenWidget(m); try { … } finally { w.close(); } … } catch (Throwable t) { showErrorMessage(t); } } } …} This program

is broken! Why?

Page 31: Subsystems: Improved exception handling for Java (DRAFT)

Problem Statement:A StackOverflowError…class Widget implements Closeable { WidgetManager m; Widget(WidgetManager m) { this.m = m; } public void close() { m.removeWidget(this); } …}class WidgetManager { int count; Widget[] widgets = new Widget[10];

Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; }

void removeWidget(Widget w) { … }}

class Program { static Widget allocGreenWidget(WidgetManager m) { Widget w = m.allocWidget(); w.setColor(Color.green); return w; } public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … Widget w = allocGreenWidget(m); try { … } finally { w.close(); } … } catch (Throwable t) { showErrorMessage(t); } } } …}

Page 32: Subsystems: Improved exception handling for Java (DRAFT)

Proposed Solution:Subsystem Cleanup Routinesclass Widget implements Closeable { Subsystem client = Subsystem.getCaller(); WidgetManager m; Widget(WidgetManager m) { client.registerCleanup(this); this.m = m; } public void close() { m.removeWidget(this); } …}class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } void removeWidget(Widget w) { reenter (s) { w.client.unregisterCleanup(w); … } }}

class Program { static Widget allocGreenWidget(WidgetManager m) { Widget w = m.allocWidget(); w.setColor(Color.green); return w; } public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … Widget w = allocGreenWidget(m); try { … } finally { w.close(); } … } catch (Throwable t) { showErrorMessage(t); } } } …}

class Subsystem { static void finish(Throwable t) { Subsystem s = getCurrent(); … while (!s.cleanupStack.isEmpty()) s.cleanupStack.peek().close(); }}

Page 33: Subsystems: Improved exception handling for Java (DRAFT)

Related Work(Under Construction) Re-entering: Similar to performing a remote procedure call in

systems where each subsystem is a separate process/thread Cancellation:

Rudys, Wallach. Termination in language-based systems. ACM TISS 5(2), 2002.

Wick, Flatt. Memory accounting without partitions. ISMM 2004. Flatt, Findler. Kill-safe synchronization abstractions. PLDI 2004. Flatt, Findler, Krishnamurthi, Felleisen. Programming languages

as operating systems. ICFP 1999. Subsystem cleanup stacks:

Similar to compensation stacks in Weimer. Finding and preventing run-time error handling mistakes. OOPSLA 2004.

Page 34: Subsystems: Improved exception handling for Java (DRAFT)

Conclusion It’s hard in Java to catch unchecked exceptions safely Many (most?) existing try-catch blocks for unchecked exceptions

are probably unsafe Many synchronized blocks are probably unsafe There is no easy and safe way to cancel a computation Subsystems make it easy to fix these problems for the example

programs Future work: Assess the severity of the problem and the

effectiveness of subsystems in large programs