Mirror of the lttng-dev mailing list
 help / color / mirror / Atom feed
From: mathieu.desnoyers@efficios.com (Mathieu Desnoyers)
Subject: [lttng-dev] [PATCH lttng-ust v2] Fix: Unsynchronized access in	LTTngTCPSessiondClient
Date: Tue, 25 Feb 2014 23:01:34 +0000 (UTC)	[thread overview]
Message-ID: <1234284751.30477.1393369294186.JavaMail.zimbra@efficios.com> (raw)
In-Reply-To: <1393363925-4773-1-git-send-email-jeremie.galarneau@efficios.com>

merged, thanks!

Mathieu

----- Original Message -----
> From: "J?r?mie Galarneau" <jeremie.galarneau@efficios.com>
> To: lttng-dev at lists.lttng.org
> Sent: Tuesday, February 25, 2014 4:32:05 PM
> Subject: [lttng-dev] [PATCH lttng-ust v2] Fix: Unsynchronized access in	LTTngTCPSessiondClient
> 
> 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
> 
> 
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
> 

-- 
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com



      reply	other threads:[~2014-02-25 23:01 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   ` [lttng-dev] [PATCH lttng-ust v2] " Jérémie Galarneau
2014-02-25 23:01     ` Mathieu Desnoyers [this message]

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=1234284751.30477.1393369294186.JavaMail.zimbra@efficios.com \
    --to=mathieu.desnoyers@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