Title: Subsystems: Improved exception handling for Java (DRAFT)
1Subsystems Improved exception handling for Java
(DRAFT)
- Bart Jacobs, Frank Piessens
2Outline
- Try-Catch Problem Solution
- Locking Problem Solution
- Cancellation Problem Solution
- Cleaning Up Problem Solution
3Outline
- Try-Catch Problem Solution
- Locking Problem Solution
- Cancellation Problem Solution
- Cleaning Up Problem Solution
4Problem StatementA Typical Try-Catch Pattern
- class Widget
- class WidgetManager
- int count
- Widget widgets new Widget10
- Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- widgetscount 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?
5Problem StatementAn OutOfMemoryError
- class Widget
- class WidgetManager
- int count
- Widget widgets new Widget10
- Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- widgetscount 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
6Problem StatementAn OutOfMemoryError
- class Widget
- class WidgetManager
- int count
- Widget widgets new Widget10
- Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- widgetscount 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)
-
-
-
-
3
4
1
2
m.count 11 m.widgets.length 10
7Problem StatementAn OutOfMemoryError
- class Widget
- class WidgetManager
- int count
- Widget widgets new Widget10
- Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- widgetscount 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)
-
-
-
-
3
4
1
2
5
m.count 12 m.widgets.length 10
8Problem StatementA Typical Try-Catch Pattern
- class Widget
- class WidgetManager
- int count
- Widget widgets new Widget10
- Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- widgetscount 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)
-
-
-
-
9Proposed SolutionRe-entering the Owner Subsystem
- class WidgetManager
- Subsystem s Subsystem.getCurrent()
- int count
- Widget widgets new Widget10
- Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount
2 - System.arraycopy(widgets, 0, ws,
0, - widgets.length)
- widgets ws
-
- widgetscount 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)
-
-
-
-
child subsystem
root subsystem
10Proposed SolutionRe-entering an Outer 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)
-
-
-
-
- class WidgetManager
- Subsystem s Subsystem.getCurrent()
- int count
- Widget widgets new Widget10
- Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount
2 - System.arraycopy(widgets, 0, ws,
0, - widgets.length)
- widgets ws
-
- widgetscount 1 w
- return w
-
-
- void removeWidget(Widget w)
11Subsystems 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
12Subsystems Basic Operation
- class 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
13Subsystems Implementation
- class Subsystem
- static StackltSubsystemgt stack new
StackltSubsystemgt() - static stack.push(new Subsystem()
- Throwable exception
- Subsystem parent
- ListltSubsystemgt children new
ArrayListltSubsystemgt() - 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)
- 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
-
14Outline
- Try-Catch Problem Solution
- Locking Problem Solution
- Cancellation Problem Solution
- Cleaning Up Problem Solution
15Problem StatementA Typical Locking Pattern
- class Widget
- class WidgetManager
- int count
- Widget widgets new Widget10
- synchronized Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- widgetscount 1 w
- return w
-
- synchronized void
- 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?
16Problem StatementAn OutOfMemoryError
- class Widget
- class WidgetManager
- int count
- Widget widgets new Widget10
- synchronized Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- widgetscount 1 w
- return w
-
- synchronized void
- 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
17Problem StatementAn OutOfMemoryError
- class Widget
- class WidgetManager
- int count
- Widget widgets new Widget10
- synchronized Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- widgetscount 1 w
- return w
-
- synchronized void
- 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
18Subsystems To The Rescue
- class WidgetManager
- Subsystem s Subsystem.getCurrent()
- int count
- Widget widgets new Widget10
- synchronized Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount
2 - System.arraycopy(widgets, 0, ws,
0, - widgets.length)
- widgets ws
-
- widgetscount 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()
-
19Subsystems To The Rescue
- class WidgetManager
- Subsystem s Subsystem.getCurrent()
- int count
- Widget widgets new Widget10
- synchronized Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount
2 - System.arraycopy(widgets, 0, ws,
0, - widgets.length)
- widgets ws
-
- widgetscount 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
20Subsystems To The Rescue
- class WidgetManager
- Subsystem s Subsystem.getCurrent()
- int count
- Widget widgets new Widget10
- synchronized Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount
2 - System.arraycopy(widgets, 0, ws,
0, - widgets.length)
- widgets ws
-
- widgetscount 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 2
In thread 1
21Subsystems To The Rescue
In main thread
- class WidgetManager
- Subsystem s Subsystem.getCurrent()
- int count
- Widget widgets new Widget10
- synchronized Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount
2 - System.arraycopy(widgets, 0, ws,
0, - widgets.length)
- widgets ws
-
- widgetscount 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 2
In thread 1
22Subsystems
- 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
23Outline
- Try-Catch Problem Solution
- Locking Problem Solution
- Cancellation Problem Solution
- Cleaning Up Problem Solution
24Problem StatementA Typical Cancellation Pattern
- class Program
- public static void main(String args)
- final WidgetManager m new
WidgetManager() - ListltTaskgt tasks new ArrayListltTaskgt()
- 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.curr
entThread()) -
- m.allocWidget()
-
- m.removeWidget()
-
- catch (Throwable t)
- 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 Widget10
- synchronized Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
This program is broken! Why?
25Problem StatementA ThreadDeath
- class Program
- public static void main(String args)
- final WidgetManager m new
WidgetManager() - ListltTaskgt tasks new ArrayListltTaskgt()
- 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.curr
entThread()) -
- m.allocWidget()
-
- m.removeWidget()
-
- catch (Throwable t)
- 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 Widget10
- synchronized Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
ThreadDeath in thread 1
m.count 11 m.widgets.length 10
26Problem StatementA ThreadDeath
- class Program
- public static void main(String args)
- final WidgetManager m new
WidgetManager() - ListltTaskgt tasks new ArrayListltTaskgt()
- 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.curr
entThread()) -
- m.allocWidget()
-
- m.removeWidget()
-
- catch (Throwable t)
- 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 Widget10
- synchronized Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
ThreadDeath in thread 1
In thread 2
m.count 12 m.widgets.length 10
27Proposed SolutionSubsystem Cancellation
- class Program
- public static void main(String args)
- final WidgetManager m new
WidgetManager() - ListltTaskgt tasks new ArrayListltTaskgt()
- 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(Subsyste
m.getCurrent()) -
- m.allocWidget()
-
- m.removeWidget()
-
- catch (Throwable t)
- class 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 Widget10
- synchronized Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
28Proposed SolutionSubsystem Cancellation
- class Program
- public static void main(String args)
- final WidgetManager m new
WidgetManager() - ListltTaskgt tasks new ArrayListltTaskgt()
- 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(Subsyste
m.getCurrent()) -
- m.allocWidget()
-
- m.removeWidget()
-
- catch (Throwable t)
- class 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 Widget10
- synchronized Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
(Child subsystem is cancelled)
ThreadDeath on entry to child
29Outline
- Try-Catch Problem Solution
- Locking Problem Solution
- Cancellation Problem Solution
- Cleaning Up Problem Solution
30Problem StatementA Typical Cleanup Pattern
- 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 Widget10
- Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- 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?
31Problem StatementA 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 Widget10
- Widget allocWidget()
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount 2
- System.arraycopy(widgets, 0, ws, 0,
- widgets.length)
- widgets ws
-
- 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)
32Proposed SolutionSubsystem Cleanup Routines
- class 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 Widget10
- Widget allocWidget()
- reenter (s)
- Widget w new Widget()
- count
- if (count widgets.length 1)
- Widget ws new Widgetcount
2 - System.arraycopy(widgets, 0, ws,
0,
- 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)
33Related 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.
34Conclusion
- Its 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