From: jeremie.galarneau@efficios.com (Jérémie Galarneau)
Subject: [lttng-dev] [PATCH lttng-ust v2] Fix: Unsynchronized access in LTTngTCPSessiondClient
Date: Tue, 25 Feb 2014 16:32:05 -0500 [thread overview]
Message-ID: <1393363925-4773-1-git-send-email-jeremie.galarneau@efficios.com> (raw)
In-Reply-To: <204474029.28925.1393099864388.JavaMail.zimbra@efficios.com>
enabledEventList is shared between the LTTngThread and eventTimer
threads but is not synchronized.
This patch changes enabledEventList's type from an ArrayList to a
synchronized HashSet.
Signed-off-by: J?r?mie Galarneau <jeremie.galarneau at efficios.com>
---
.../org/lttng/ust/jul/LTTngTCPSessiondClient.java | 129 ++++++++++++---------
1 file changed, 74 insertions(+), 55 deletions(-)
diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java
index 25d1cb2..35f768f 100644
--- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java
+++ b/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java
@@ -30,10 +30,14 @@ 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;
@@ -57,7 +61,8 @@ public class LTTngTCPSessiondClient {
private Semaphore registerSem;
private Timer eventTimer;
- private List<LTTngEvent> enabledEventList = new ArrayList<LTTngEvent>();
+ private Set<LTTngEvent> enabledEventSet =
+ Collections.synchronizedSet(new HashSet<LTTngEvent>());
/*
* Map of Logger objects that have been enabled. They are indexed by name.
*/
@@ -82,65 +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<LTTngEvent> tmpList = new ArrayList<LTTngEvent>(enabledEventList);
-
- LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new
- LTTngSessiondCmd2_4.sessiond_enable_handler();
- for (LTTngEvent event: tmpList) {
- int ret;
- Logger logger;
-
+ synchronized (enabledEventSet) {
+ LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new
+ LTTngSessiondCmd2_4.sessiond_enable_handler();
/*
- * 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...
+ * 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.
*/
- logger = enabledLoggers.get(event.name);
- if (logger != null) {
- continue;
- }
+ Set<LTTngEvent> modifiedEvents = new HashSet<LTTngEvent>();
+ Iterator<LTTngEvent> it = enabledEventSet.iterator();
- /*
- * 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) {
- event.logLevel.level = handler.logLevelAll;
- event.logLevel.type = handler.logLevelTypeAll;
- }
+ while (it.hasNext()) {
+ int ret;
+ Logger logger;
+ LTTngEvent event = it.next();
- /*
- * 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 list.
+ * 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...
*/
- enableCmd.execute(handler, enabledLoggers);
- continue;
- }
+ logger = enabledLoggers.get(event.name);
+ if (logger != null) {
+ continue;
+ }
- ret = enableCmd.enableLogger(handler, event, enabledLoggers);
- if (ret == 1) {
- /* Enabled so remove the event from the list. */
- enabledEventList.remove(event);
+ /*
+ * 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);
@@ -274,12 +295,10 @@ public class LTTngTCPSessiondClient {
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.
*/
- if (enabledEventList.contains(event) == false) {
- enabledEventList.add(event);
- }
+ enabledEventSet.add(event);
}
data = enableCmd.getBytes();
break;
--
1.9.0
next prev parent reply other threads:[~2014-02-25 21:32 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-20 16:22 [lttng-dev] [PATCH lttng-ust] " Jérémie Galarneau
2014-02-22 16:12 ` Mathieu Desnoyers
2014-02-22 19:15 ` Jérémie Galarneau
2014-02-22 20:08 ` Mathieu Desnoyers
2014-02-22 20:11 ` Mathieu Desnoyers
2014-02-22 20:19 ` Jérémie Galarneau
2014-02-25 21:32 ` Jérémie Galarneau [this message]
2014-02-25 23:01 ` [lttng-dev] [PATCH lttng-ust v2] " Mathieu Desnoyers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1393363925-4773-1-git-send-email-jeremie.galarneau@efficios.com \
--to=jeremie.galarneau@efficios.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox