FELIX-3623: made the locks used to notify listeners of new log entries as small as possible by breaking them in separate locks. Also notify all listeners of all current log entries, instead of the 'single delivery' policy used before.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1370708 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/log/src/main/java/org/apache/felix/log/LogListenerThread.java b/log/src/main/java/org/apache/felix/log/LogListenerThread.java
index 4007685..854baa4 100644
--- a/log/src/main/java/org/apache/felix/log/LogListenerThread.java
+++ b/log/src/main/java/org/apache/felix/log/LogListenerThread.java
@@ -33,8 +33,6 @@
  */
 final class LogListenerThread extends Thread
 {
-    // Whether the thread is stopping or not.
-    private boolean m_stopping = false;
     // The list of entries waiting to be delivered to the log listeners.
     private final List m_entriesToDeliver = new ArrayList();
     // The list of listeners.
@@ -87,7 +85,10 @@
      */
     int getListenerCount()
     {
-        return m_listeners.size();
+        synchronized (m_listeners)
+        {
+            return m_listeners.size();
+        }
     }
 
     /**
@@ -97,8 +98,7 @@
     {
         synchronized (m_entriesToDeliver)
         {
-            m_stopping = true;
-            m_entriesToDeliver.notifyAll();
+            interrupt();
         }
     }
 
@@ -108,34 +108,11 @@
      */
     public void run()
     {
-        boolean stop = false;
-
-        for (; !stop;)
+        while (!isInterrupted())
         {
+            List entriesToDeliver = new ArrayList();
             synchronized (m_entriesToDeliver)
             {
-                if (!m_entriesToDeliver.isEmpty())
-                {
-                    LogEntry entry = (LogEntry) m_entriesToDeliver.remove(0);
-
-                    synchronized (m_listeners)
-                    {
-                        Iterator listenerIt = m_listeners.iterator();
-                        while (listenerIt.hasNext())
-                        {
-                            try
-                            {
-                                LogListener listener = (LogListener) listenerIt.next();
-                                listener.logged(entry);
-                            }
-                            catch (Throwable t)
-                            {
-                                // catch and discard any exceptions thrown by the listener
-                            }
-                        }
-                    }
-                }
-
                 if (m_entriesToDeliver.isEmpty())
                 {
                     try
@@ -144,14 +121,49 @@
                     }
                     catch (InterruptedException e)
                     {
-                        // do nothing
+                        // the interrupt-flag is cleared; so, let's play nice and 
+                        // interrupt this thread again to stop it...
+                        interrupt();
                     }
                 }
+                else 
+                {
+                    // Copy all current entries and deliver them in a single go...
+                    entriesToDeliver.addAll(m_entriesToDeliver);
+                    m_entriesToDeliver.clear();
+                }
             }
-
-            if (m_stopping)
+            
+            if (!entriesToDeliver.isEmpty())
             {
-                stop = true;
+                // Take a snapshot of all current listeners and deliver all
+                // pending messages to them...
+                List listeners = new ArrayList();
+                synchronized (m_listeners) 
+                {
+                    listeners.addAll(m_listeners);
+                }
+
+                Iterator entriesIt = entriesToDeliver.iterator();
+                while (entriesIt.hasNext()) 
+                {
+                    LogEntry entry = (LogEntry) entriesIt.next();
+                    
+                    Iterator listenerIt = listeners.iterator();
+                    while (listenerIt.hasNext())
+                    {
+                        LogListener listener = (LogListener) listenerIt.next();
+                        
+                        try
+                        {
+                            listener.logged(entry);
+                        }
+                        catch (Throwable t)
+                        {
+                            // catch and discard any exceptions thrown by the listener
+                        }
+                    }
+                }
             }
         }
     }