[FELIX-4336] Use smarter thread locals for ThreadIo so that streams that have been deactivated won't be used and delegate to the previous stream instead

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1546581 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/Marker.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/Marker.java
index 95c50e5..84dc7ce 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/Marker.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/Marker.java
@@ -23,26 +23,41 @@
 
 public class Marker
 {
-    Marker previous;
+    final Marker previous;
     InputStream in;
     PrintStream out;
     PrintStream err;
-    ThreadIOImpl parent;
+    volatile boolean deactivated;
 
-    public Marker(ThreadIOImpl parent, InputStream in, PrintStream out, PrintStream err, Marker previous)
+    public Marker(InputStream in, PrintStream out, PrintStream err, Marker previous)
     {
         this.previous = previous;
-        this.parent = parent;
         this.in = in;
         this.out = out;
         this.err = err;
     }
 
-    Marker activate()
+    public InputStream getIn()
     {
-        parent.in.setStream(in);
-        parent.out.setStream(out);
-        parent.err.setStream(err);
-        return previous;
+        return deactivated ? previous.getIn() : in;
+    }
+
+    public PrintStream getOut()
+    {
+        return deactivated ? previous.getOut() : out;
+    }
+
+    public PrintStream getErr()
+    {
+        return deactivated ? previous.getErr() : err;
+    }
+
+    void deactivate()
+    {
+        deactivated = true;
+        // Set to null for garbage collection
+        in = null;
+        out = null;
+        err = null;
     }
 }
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadIOImpl.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadIOImpl.java
index c4e2a12..bf50878 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadIOImpl.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadIOImpl.java
@@ -28,10 +28,19 @@
 public class ThreadIOImpl implements ThreadIO
 {
     static private final Logger log = Logger.getLogger(ThreadIOImpl.class.getName());
-    ThreadPrintStream err = new ThreadPrintStream(System.err);
-    ThreadPrintStream out = new ThreadPrintStream(System.out);
-    ThreadInputStream in = new ThreadInputStream(System.in);
-    ThreadLocal<Marker> current = new InheritableThreadLocal<Marker>();
+
+    final Marker defaultMarker = new Marker(System.in, System.out, System.err, null);
+    final ThreadPrintStream err = new ThreadPrintStream(this, System.err, true);
+    final ThreadPrintStream out = new ThreadPrintStream(this, System.out, false);
+    final ThreadInputStream in = new ThreadInputStream(this, System.in);
+    final ThreadLocal<Marker> current = new InheritableThreadLocal<Marker>()
+    {
+        @Override
+        protected Marker initialValue()
+        {
+            return defaultMarker;
+        }
+    };
 
     public void start()
     {
@@ -46,9 +55,9 @@
 
     public void stop()
     {
-        System.setErr(err.dflt);
-        System.setOut(out.dflt);
-        System.setIn(in.dflt);
+        System.setErr(defaultMarker.err);
+        System.setOut(defaultMarker.out);
+        System.setIn(defaultMarker.in);
     }
 
     private void checkIO()
@@ -72,6 +81,20 @@
         }
     }
 
+    Marker current()
+    {
+        Marker m = current.get();
+        if (m.deactivated)
+        {
+            while (m.deactivated)
+            {
+                m = m.previous;
+            }
+            current.set(m);
+        }
+        return m;
+    }
+
     public void close()
     {
         checkIO(); // derek
@@ -80,18 +103,10 @@
         {
             throw new IllegalStateException("No thread io active");
         }
-
-        Marker previous = top.previous;
-        if (previous == null)
+        if (top != defaultMarker)
         {
-            in.end();
-            out.end();
-            err.end();
-        }
-        else
-        {
-            this.current.set(previous);
-            previous.activate();
+            top.deactivate();
+            this.current.set(top.previous);
         }
     }
 
@@ -101,8 +116,7 @@
         assert out != null;
         assert err != null;
         checkIO(); // derek
-        Marker marker = new Marker(this, in, out, err, current.get());
+        Marker marker = new Marker(in, out, err, current.get());
         this.current.set(marker);
-        marker.activate();
     }
 }
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadInputStream.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadInputStream.java
index 9f27c59..893d121 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadInputStream.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadInputStream.java
@@ -23,39 +23,19 @@
 

 public class ThreadInputStream extends InputStream

 {

-    ThreadLocal<InputStream> map = new InheritableThreadLocal<InputStream>();

-    InputStream dflt;

+    final InputStream dflt;

+    final ThreadIOImpl io;

 

-    public ThreadInputStream(InputStream in)

+    public ThreadInputStream(ThreadIOImpl threadIO, InputStream in)

     {

+        io = threadIO;

         dflt = in;

     }

 

     private InputStream getCurrent()

     {

-        InputStream in = map.get();

-        if (in != null)

-        {

-            return in;

-        }

-        return dflt;

-    }

-

-    public void setStream(InputStream in)

-    {

-        if (in != dflt && in != this)

-        {

-            map.set(in);

-        }

-        else

-        {

-            map.remove();

-        }

-    }

-

-    public void end()

-    {

-        map.remove();

+        Marker marker = io.current();

+        return marker.getIn();

     }

 

     /**

diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadPrintStream.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadPrintStream.java
index e8893f6..6cd14bc 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadPrintStream.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/threadio/ThreadPrintStream.java
@@ -25,40 +25,22 @@
 

 public class ThreadPrintStream extends PrintStream

 {

-    PrintStream dflt;

-    ThreadLocal<PrintStream> map = new InheritableThreadLocal<PrintStream>();

+    final PrintStream dflt;

+    final ThreadIOImpl io;

+    final boolean errorStream;

 

-    public ThreadPrintStream(PrintStream out)

+    public ThreadPrintStream(ThreadIOImpl threadIO, PrintStream out, boolean error)

     {

         super(out);

         dflt = out;

+        io = threadIO;

+        errorStream = error;

     }

 

     public PrintStream getCurrent()

     {

-        PrintStream out = map.get();

-        if (out != null)

-        {

-            return out;

-        }

-        return dflt;

-    }

-

-    public void setStream(PrintStream out)

-    {

-        if (out != dflt && out != this)

-        {

-            map.set(out);

-        }

-        else

-        {

-            map.remove();

-        }

-    }

-

-    public void end()

-    {

-        map.remove();

+        Marker marker = io.current();

+        return errorStream ? marker.getErr() : marker.getOut();

     }

 

     /**