Fix: Unsynchronized access in LTTngTCPSessiondClient
[lttng-ust.git] / liblttng-ust-jul / org / lttng / ust / jul / LTTngTCPSessiondClient.java
index b89deb818c4702514d86842570abf9a9aac16dcd..35f768f30c5b88d27d09cd7a498422cd9a16d222 100644 (file)
@@ -29,9 +29,15 @@ import java.io.DataInputStream;
 import java.net.*;
 import java.lang.management.ManagementFactory;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
+import java.util.logging.Logger;
+import java.util.Collections;
 
 class USTRegisterMsg {
        public static int pid;
@@ -55,7 +61,12 @@ public class LTTngTCPSessiondClient {
        private Semaphore registerSem;
 
        private Timer eventTimer;
-       private List<String> enabledEventList = new ArrayList<String>();
+       private Set<LTTngEvent> enabledEventSet =
+               Collections.synchronizedSet(new HashSet<LTTngEvent>());
+       /*
+        * Map of Logger objects that have been enabled. They are indexed by name.
+        */
+       private HashMap<String, Logger> enabledLoggers = new HashMap<String, Logger>();
        /* Timer delay at each 5 seconds. */
        private final static long timerDelay = 5 * 1000;
        private static boolean timerInitialized;
@@ -76,20 +87,81 @@ public class LTTngTCPSessiondClient {
                this.eventTimer.scheduleAtFixedRate(new TimerTask() {
                        @Override
                        public void run() {
-                               /*
-                                * We have to make a copy here since it is possible that the
-                                * enabled event list is changed during an iteration on it.
-                                */
-                               List<String> tmpList = new ArrayList<String>(enabledEventList);
-
-                               LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new
-                                       LTTngSessiondCmd2_4.sessiond_enable_handler();
-                               for (String strEventName: tmpList) {
-                                       enableCmd.name = strEventName;
-                                       if (enableCmd.execute(handler) == null) {
-                                               enabledEventList.remove(strEventName);
+                               synchronized (enabledEventSet) {
+                                       LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new
+                                               LTTngSessiondCmd2_4.sessiond_enable_handler();
+                                       /*
+                                        * Modifying events in a Set will raise a
+                                        * ConcurrentModificationException. Thus, we remove an event
+                                        * and add its modified version to modifiedEvents when a
+                                        * modification is necessary.
+                                        */
+                                       Set<LTTngEvent> modifiedEvents = new HashSet<LTTngEvent>();
+                                       Iterator<LTTngEvent> it = enabledEventSet.iterator();
+
+                                       while (it.hasNext()) {
+                                               int ret;
+                                               Logger logger;
+                                               LTTngEvent event = it.next();
+
+                                               /*
+                                                * Check if this Logger name has been enabled already. Note
+                                                * that in the case of "*", it's never added in that hash
+                                                * table thus the enable command does a lookup for each
+                                                * logger name in that hash table for the * case in order
+                                                * to make sure we don't enable twice the same logger
+                                                * because JUL apparently accepts that the *same*
+                                                * LogHandler can be added twice on a Logger object...
+                                                * don't ask...
+                                                */
+                                               logger = enabledLoggers.get(event.name);
+                                               if (logger != null) {
+                                                       continue;
+                                               }
+
+                                               /*
+                                                * Set to one means that the enable all event has been seen
+                                                * thus event from that point on must use loglevel for all
+                                                * events. Else the object has its own loglevel.
+                                                */
+                                               if (handler.logLevelUseAll == 1) {
+                                                       it.remove();
+                                                       event.logLevel.level = handler.logLevelAll;
+                                                       event.logLevel.type = handler.logLevelTypeAll;
+                                                       modifiedEvents.add(event);
+                                               }
+
+                                               /*
+                                                * The all event is a special case since we have to iterate
+                                                * over every Logger to see which one was not enabled.
+                                                */
+                                               if (event.name.equals("*")) {
+                                                       enableCmd.name = event.name;
+                                                       enableCmd.lttngLogLevel = event.logLevel.level;
+                                                       enableCmd.lttngLogLevelType = event.logLevel.type;
+                                                       /*
+                                                        * The return value is irrelevant since the * event is
+                                                        * always kept in the set.
+                                                        */
+                                                       enableCmd.execute(handler, enabledLoggers);
+                                                       continue;
+                                               }
+
+                                               ret = enableCmd.enableLogger(handler, event, enabledLoggers);
+                                               if (ret == 1) {
+                                                       /* Enabled so remove the event from the set. */
+                                                       if (!modifiedEvents.remove(event)) {
+                                                               /*
+                                                                * event can only be present in one of
+                                                                * the sets.
+                                                                */
+                                                               it.remove();
+                                                       }
+                                               }
                                        }
+                                       enabledEventSet.addAll(modifiedEvents);
                                }
+
                        }
                }, this.timerDelay, this.timerDelay);
 
@@ -212,7 +284,7 @@ public class LTTngTCPSessiondClient {
                                }
                                case CMD_ENABLE:
                                {
-                                       String event_name;
+                                       LTTngEvent event;
                                        LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd =
                                                new LTTngSessiondCmd2_4.sessiond_enable_handler();
                                        if (data == null) {
@@ -220,13 +292,13 @@ public class LTTngTCPSessiondClient {
                                                break;
                                        }
                                        enableCmd.populate(data);
-                                       event_name = enableCmd.execute(this.handler);
-                                       if (event_name != null) {
+                                       event = enableCmd.execute(this.handler, this.enabledLoggers);
+                                       if (event != null) {
                                                /*
-                                                * Add the event to the list so it can be enabled if
+                                                * Add the event to the set so it can be enabled if
                                                 * the logger appears at some point in time.
                                                 */
-                                               enabledEventList.add(event_name);
+                                               enabledEventSet.add(event);
                                        }
                                        data = enableCmd.getBytes();
                                        break;
This page took 0.049993 seconds and 4 git commands to generate.