Repository: MDSplus/mdsplus
Pull request #2904: Fix:remove race conditions leading to deadlock
Author: login: GabrieleManduchi
Labels: name: bug
description: An unexpected problem or unintended behavior
name: api/java
description: Relates to one of the Java APIs
Created: 2025-05-05T11:53:07Z | Merged: 2025-05-09T15:30:48Z

When interacting with jScope during automatic update, jScope often freezes. 
This is due to deadlock conditions that occurred when  an update event was received during interaction operations (e.g. zooming). 
This issue has been fixed by removing the useless synchronized option to several methods, and ensuring that critical concurrent operations were carried out by the main Swing thread. 

In addition, a fix has been carried out in the resampling management, mainly due to the usage of float instead of double for the specification of time windows. This led to missing resampling for high frequencies. For this purpose, a new routine (GetXYSignalDoubleLimits) has been added to mdsmisc/ScopeUtilities.c. This routine is called by the new jScope version. The older routine (GetXYSignal) has been retained for compatibility with the older jScope versions. 



Diff:
diff --git a/java/jscope/src/main/java/mds/jscope/MdsWaveInterface.java b/java/jscope/src/main/java/mds/jscope/MdsWaveInterface.java
index 1a3ca8e8dd..2d9dc9f611 100644
--- a/java/jscope/src/main/java/mds/jscope/MdsWaveInterface.java
+++ b/java/jscope/src/main/java/mds/jscope/MdsWaveInterface.java
@@ -918,7 +918,7 @@ public int mode2DStringToCode(String mode)
 		return 0;
 	}
 
-	public synchronized void refresh() throws Exception
+	public  void refresh() throws Exception
 	{
 		try
 		{
@@ -941,7 +941,7 @@ public synchronized void refresh() throws Exception
 		}
 	}
 
-	public synchronized boolean refreshOnEvent() throws Exception
+	public boolean refreshOnEvent() throws Exception
 	{
 		final long shots[] = GetShots();
 		if (shots == null)
@@ -957,7 +957,6 @@ public synchronized boolean refreshOnEvent() throws Exception
 			{
 				if (!signals[sigIdx].supportsStreaming() || !signals[sigIdx].updateSignal())
 					return false;
-				signals[sigIdx].mergeRegions();
 			}
 		}
 		return true;
diff --git a/java/jscope/src/main/java/mds/jscope/jScopeFacade.java b/java/jscope/src/main/java/mds/jscope/jScopeFacade.java
index 77b00b8e6e..46a1983dd0 100644
--- a/java/jscope/src/main/java/mds/jscope/jScopeFacade.java
+++ b/java/jscope/src/main/java/mds/jscope/jScopeFacade.java
@@ -2478,6 +2478,17 @@ private void ToFile(PrintWriter out) throws IOException
 	}
 
 	public void UpdateAllWaves()
+        {
+            SwingUtilities.invokeLater(new Runnable()
+            {
+                    @Override
+                    public void run()
+                    {
+                            intUpdateAllWaves();
+                    }
+            });
+        }
+	public void intUpdateAllWaves()
 	{
 		final String s = shot_t.getText();
 		final String s1 = def_values.shot_str;
diff --git a/java/jscope/src/main/java/mds/jscope/jScopeMultiWave.java b/java/jscope/src/main/java/mds/jscope/jScopeMultiWave.java
index 40e8f374e0..56ace9c283 100644
--- a/java/jscope/src/main/java/mds/jscope/jScopeMultiWave.java
+++ b/java/jscope/src/main/java/mds/jscope/jScopeMultiWave.java
@@ -210,7 +210,7 @@ public void jScopeErase()
 		wi.Erase();
 	}
 
-	public synchronized void jScopeWaveUpdate()
+	public void jScopeWaveUpdate()
 	{
 		if (wi.isAddSignal())
 		{
diff --git a/java/jscope/src/main/java/mds/jscope/jScopeWaveContainer.java b/java/jscope/src/main/java/mds/jscope/jScopeWaveContainer.java
index ba5f06a7ef..09f67ba825 100644
--- a/java/jscope/src/main/java/mds/jscope/jScopeWaveContainer.java
+++ b/java/jscope/src/main/java/mds/jscope/jScopeWaveContainer.java
@@ -118,7 +118,7 @@ public void AbortUpdate()
 		abort = true;
 	}
 
-	public synchronized void AddAllEvents(UpdateEventListener l) throws IOException
+	public  void AddAllEvents(UpdateEventListener l) throws IOException
 	{
 		jScopeMultiWave w;
 		if (dp == null)
@@ -588,7 +588,7 @@ private JFrame GetFrameParent()
 		return (JFrame) c;
 	}
 
-	public synchronized void getjScopeMultiWave()
+	public  void getjScopeMultiWave()
 	{
 		wave_all = new jScopeMultiWave[getGridComponentCount()];
 		for (int i = 0, k = 0; i < 4; i++)
@@ -789,7 +789,7 @@ public void processWaveformEvent(WaveformEvent e)
 		}
 	}
 
-	public synchronized void Refresh(jScopeMultiWave w, String label)
+	public  void Refresh(jScopeMultiWave w, String label)
 	{
 		Point p = null;
 		if (add_sig)
@@ -1134,7 +1134,7 @@ public void SetMainShot(String shot_str)
 			{
 				main_shot_str = null;
 				main_shot_error = "Main Shots evaluations error : \n" + exc.getMessage();
-				JOptionPane.showMessageDialog(this, main_shot_error, "alert SetMainShot", JOptionPane.ERROR_MESSAGE);
+				//JOptionPane.showMessageDialog(this, main_shot_error, "alert SetMainShot", JOptionPane.ERROR_MESSAGE);
 			}
 		}
 	}
@@ -1302,7 +1302,7 @@ public void ToFile(PrintWriter out, String prompt) throws IOException
 		}
 	}
 
-	public synchronized void UpdateAllWave() throws Exception
+	public  void UpdateAllWave() throws Exception
 	{
 		WaveContainerEvent wce;
 		try
diff --git a/java/jscope/src/main/java/mds/provider/MdsDataProvider.java b/java/jscope/src/main/java/mds/provider/MdsDataProvider.java
index cde9ddfd9c..3602c4c2cc 100644
--- a/java/jscope/src/main/java/mds/provider/MdsDataProvider.java
+++ b/java/jscope/src/main/java/mds/provider/MdsDataProvider.java
@@ -271,7 +271,6 @@ class SimpleFrameData implements FrameData
 		private float times[] = null;
 		private Dimension dim = null;
 		private int header_size = 0;
-
 		public SimpleFrameData(String in_y, String in_x, float time_min, float time_max) throws Exception
 		{
 			int i;
@@ -635,14 +634,14 @@ public XYData getData(double xmin, double xmax, int numPoints, boolean isLong) t
 			}
 			else
 			{
-				args.addElement(new Descriptor(null, new float[]
-				{ (float) xmin }));
-				args.addElement(new Descriptor(null, new float[]
-				{ (float) xmax }));
+				args.addElement(new Descriptor(null, new double[]
+				{ (double) xmin }));
+				args.addElement(new Descriptor(null, new double[]
+				{ (double) xmax }));
 			}
 			args.addElement(new Descriptor(null, new int[]
 			{ numPoints }));
-			byte[] retData;
+			byte[] retData = null;
 			int nSamples;
 			try
 			{
@@ -651,11 +650,30 @@ public XYData getData(double xmin, double xmax, int numPoints, boolean isLong) t
 				if (numPoints == Integer.MAX_VALUE)
 					throw new Exception("Use Old Method for getting data");
 				if (isLong)
-//                      retData = GetByteArray(setTimeContext+" MdsMisc->GetXYSignalLongTimes:DSC", args);
 					retData = GetByteArray(" MdsMisc->GetXYSignalLongTimes:DSC", args);
 				else
-//                      retData = GetByteArray(setTimeContext+" MdsMisc->GetXYSignal:DSC", args);
-					retData = GetByteArray(" MdsMisc->GetXYSignal:DSC", args);
+                                {
+                                    try {
+ 					retData = GetByteArray(" MdsMisc->GetXYSignalDoubleLimits:DSC", args);
+                                    }catch(Exception exc)
+                                    {
+                                        //Try old method in case the mdsip server is not up-to-date
+                                         final Vector<Descriptor> newArgs = new Vector<>();
+                                         for(int i = 0; i < args.size() - 3; i++)
+                                        {
+                                            newArgs.addElement(args.elementAt(i));
+                                        }
+                                        newArgs.addElement(new Descriptor(null, new float[]
+                                                { (float) xmin }));
+                                        newArgs.addElement(new Descriptor(null, new float[]
+                                                { (float) xmax }));
+                                        newArgs.addElement(new Descriptor(null, new int[]
+                                                { numPoints }));
+                                         try {
+                                                retData = GetByteArray(" MdsMisc->GetXYSignal:DSC", newArgs);
+                                         } catch(Exception exc1){System.out.println(exc1);}
+                                    }
+                                }
 				/*
 				 * Decode data: Format: -retResolution(float) ----Gabriele Feb 2019 NEW: if
 				 * retResolution == 0 then the following int is the number of bytes of the error
@@ -706,8 +724,14 @@ else if (type == 2) // double X
 				{
 					final double[] x = new double[nSamples];
 					for (int i = 0; i < nSamples; i++)
+                                        {
 						x[i] = dis.readDouble();
-					res = new XYData(x, y, dRes);
+                                                if(i > 0 && x[i-1] > x[i])
+                                                {
+                                                    System.out.println("Internal error: non increasing dimension ("+i+" "+nSamples+")");
+                                                }
+                                        }        
+                                        res = new XYData(x, y, dRes);
 				}
 				else // float X
 				{
@@ -795,7 +819,7 @@ public void getDataAsync(double lowerBound, double upperBound, int numPoints)
 		@Override
 		public int getNumDimension() throws IOException
 		{
-			if (numDimensions != UNKNOWN)
+            if (numDimensions != UNKNOWN)
 				return numDimensions;
 			String expr;
 			if (_jscope_set)
@@ -803,9 +827,11 @@ public int getNumDimension() throws IOException
 			else
 			{
 				if (segmentMode == SEGMENTED_YES)
-					expr = "shape(GetSegment(" + segmentNodeName + ",0))";
-//	            expr = "shape(GetSegment(" + in_y +",0))";
-				else
+                                {
+                                    expr = "shape("+in_y.replace(segmentNodeName, "GetSegment("+segmentNodeName+",0)")+")";
+//	expr = "shape(GetSegment(" + segmentNodeName + ",0))";
+                                }
+	        		else
 				{
 					_jscope_set = true;
 					expr = "( _jscope_" + v_idx + " = (" + in_y + ";), shape(_jscope_" + v_idx + "))";
@@ -1106,11 +1132,15 @@ class UpdateDescriptor
 				this.isXLong = isXLong;
 				this.updateTime = updateTime;
 			}
+                        public String toString()
+                        {
+                            return "Lower Bound: "+updateLowerBound+"\nUpper Bound: "+updateUpperBound+"\nupdatePoints: "+updatePoints;
+                        }
 		}
 
 		boolean enabled = true;
 		Vector<UpdateDescriptor> requestsV = new Vector<>();
-
+                UpdateDescriptor currUpdate;
 		boolean stopWorker = false;
 
 		synchronized void enableAsyncUpdate(boolean enabled)
@@ -1153,10 +1183,14 @@ public void run()
 					if (!enabled)
 						break;
 					// Take most recent request
-					final UpdateDescriptor currUpdate = requestsV.elementAt(requestsV.size() - 1);
+					currUpdate = requestsV.elementAt(requestsV.size() - 1);
 					try
 					{
 						requestsV.removeElementAt(requestsV.size() - 1);
+                                                //requestsV.clear(); //Older requests are ignored
+                                                
+                                                
+                                                
 						final XYData currData = currUpdate.simpleWaveData.getData(currUpdate.updateLowerBound,
 								currUpdate.updateUpperBound, currUpdate.updatePoints, currUpdate.isXLong);
 						if (debug)
@@ -1179,6 +1213,8 @@ public void run()
 					{
 						final Date d = new Date();
 						System.out.println(d + " Error in asynchUpdate: " + exc);
+                                                System.out.println(currUpdate);
+                                                exc.printStackTrace();
 					}
 				}
 			}
@@ -1376,7 +1412,7 @@ protected synchronized boolean CheckOpen(String experiment, long shot, String de
 		}
 		if (open)
 		{
-			if (defaultNode != null && (prev_default_node == null || !defaultNode.equals(prev_default_node)))
+			if (defaultNode != null && (prev_default_node == null || (!defaultNode.trim().equals("") && !defaultNode.equals(prev_default_node))))
 			{
 				Descriptor descr;
 				if (default_node.trim().charAt(0) == '\\')
@@ -1395,6 +1431,7 @@ else if (defaultNode == null && prev_default_node != null)
 				mds.MdsValue("TreeSetDefault(\"\\\\::TOP\")");
 				prev_default_node = null;
 			}
+                        prev_default_node = default_node;
 		}
 		return true;
 	}
diff --git a/java/jscope/src/main/java/mds/wave/Grid.java b/java/jscope/src/main/java/mds/wave/Grid.java
index 8f27f9757e..e572a94236 100644
--- a/java/jscope/src/main/java/mds/wave/Grid.java
+++ b/java/jscope/src/main/java/mds/wave/Grid.java
@@ -13,6 +13,7 @@ public class Grid implements Serializable
 	 *
 	 */
 	private static final long serialVersionUID = 1L;
+	private static final int MAX_STEPS = 1000; //Maximum number of steps in the tick selection agorithm
 	static final long dayMilliSeconds = 86400000; // 24 * 60 * 60 * 1000;
 	final static int IS_X = 0, IS_Y = 1;
 	public final static int IS_DOTTED = 0;
@@ -64,8 +65,8 @@ public Grid(double xmax, double ymax, double xmin, double ymin, boolean xlog, bo
 		y_values = new double[50];
 		this.xmax = xmax;
 		x_dim = BuildGrid(x_values, IS_X, xmax, ymax, xmin, ymin, xlog, ylog);
-		y_dim = BuildGrid(y_values, IS_Y, xmax, ymax, xmin, ymin, xlog, ylog);
-	}
+ 		y_dim = BuildGrid(y_values, IS_Y, xmax, ymax, xmin, ymin, xlog, ylog);
+ 	}
 
 	private int BuildGrid(double val[], int mode, double xmax, double ymax, double xmin, double ymin, boolean xlog,
 			boolean ylog)
@@ -125,8 +126,11 @@ private int BuildGrid(double val[], int mode, double xmax, double ymax, double x
 		curr = (long) (curr_min / step) * step;
 		if (curr > curr_min)
 			curr -= (long) ((curr - curr_min) / step) * step;
-		while (curr >= curr_min)
+                int maxSteps = MAX_STEPS;
+                for(int j = 0; j < maxSteps && (curr >= curr_min); j++)
+                {
 			curr -= step;
+                }
 		for (i = 0; i < 50 && curr < curr_max + step; i++)
 		{
 			val[i] = (long) (curr / step + 0.5) * step;
diff --git a/java/jscope/src/main/java/mds/wave/Signal.java b/java/jscope/src/main/java/mds/wave/Signal.java
index f271939c47..cd1ed9dc68 100644
--- a/java/jscope/src/main/java/mds/wave/Signal.java
+++ b/java/jscope/src/main/java/mds/wave/Signal.java
@@ -20,6 +20,9 @@
  */
 public class Signal implements WaveDataListener
 {
+        static final int DIM_THRESHOLD = 5000; //Number of 1D data points triggering reallocation of X and Y arrays
+    
+    
 	static class RegionDescriptor
 	{
 		double lowerBound, upperBound;
@@ -53,7 +56,13 @@ void addRegion(RegionDescriptor newReg)
 			// Skip disjoint regions with lower bounds
 			if (newReg.upperBound < newReg.lowerBound)
 			{
-				System.err.println("INTERNAL ERROR: LOWER BOUND > UPPER BOUND!!!!!");
+				System.err.println("INTERNAL ERROR : LOWER BOUND "+ newReg.lowerBound +" > UPPER BOUND ("+newReg.upperBound+")");
+                                try {
+                                    throw(new Exception());
+                                }catch(Exception exc)
+                                {
+                                    exc.printStackTrace();
+                                }
 			}
 			int idx;
 			RegionDescriptor currRegion;
@@ -170,8 +179,9 @@ void appendRegion(RegionDescriptor newReg)
 			}
 		}
 
+                
 		// Check if the passed interval intersects any low resolution region
-		Vector<RegionDescriptor> getLowerResRegions(double lowerInt, double upperInt, double resolution)
+		synchronized Vector<RegionDescriptor> getLowerResRegions(double lowerInt, double upperInt, double resolution)
 		{
 			final Vector<RegionDescriptor> retRegions = new Vector<>();
 			for (int i = 0; i < lowResRegions.size(); i++)
@@ -1457,18 +1467,69 @@ void checkIncreasingX2D()
 		}
 	}
 
-	@Override
-	public void dataRegionUpdated(double[] regX, float[] regY, double resolution)
-	{
+        static final int UPDATE_LIMITS = 0;
+        static final int DO_NOT_UPDATE_LIMITS = 1;
+        static final int UPDATE_PENDING = 2;
+                
+        @Override       
+        public void dataRegionUpdated(double[] inRegX, float[] inRegY, double resolution)
+        {
+            int updateStatus = updateDataRegion(inRegX, inRegY, resolution);
+            if(updateStatus == UPDATE_LIMITS)
+            {
+                fireSignalUpdated(true);
+            }
+            else if (updateStatus == DO_NOT_UPDATE_LIMITS)
+            {
+                 fireSignalUpdated(false);
+           }
+        }
+        
+        
+
+	public synchronized int updateDataRegion(double[] inRegX, float[] inRegY, double resolution)
+	{
+            
+            if(inRegX != null && inRegX.length > 1 && inRegX[inRegX.length - 1] < inRegX[0])
+            {
+                System.out.println("INTERNAL ERROR IN UPDATE DATA REGION REGION: Inconsistent dimension, update skipped");
+                return UPDATE_PENDING;
+            }
+            double[] regX;
+            float[] regY;
+            try {
+                if(inRegX.length == inRegY.length)
+                {
+                    regX = inRegX;
+                    regY = inRegY;
+                }
+                else if (inRegX.length > inRegY.length)
+                {
+                    regY = inRegY;
+                    regX = new double[inRegY.length];
+                    System.arraycopy(inRegX, 0, regX, 0, inRegY.length);
+                }
+                else // inRegX.length < inRegY.length
+                {
+                    regX = inRegX;
+                    regY = new float[inRegX.length];
+                    System.arraycopy(inRegY, 0, regY, 0, inRegX.length);
+                }
+                
 		if (regX == null || regX.length == 0)
-			return;
+			return UPDATE_PENDING;
+                if(regX.length != regY.length)
+                {
+                    System.out.println("INTERNAL ERROR in Signal.dataRegionUpdated: regX.length = "+regX.length+"  regY.length = "+regY.length);
+                    return UPDATE_PENDING;
+                }
 		if (debug)
 			System.out.println("dataRegionUpdated " + resolutionManager.lowResRegions.size() + " new data len:"
 					+ regX.length + " XMIN:" + regX[0] + "  XMAX: " + regX[regX.length - 1]);
 		if (freezeMode != NOT_FREEZED) // If zooming in ANY part of the signal
 		{
 			pendingUpdatesV.addElement(new XYData(regX, regY, resolution, true, regX[0], regX[regX.length - 1]));
-			return;
+			return UPDATE_PENDING;
 		}
 		int samplesBefore, samplesAfter;
 		// if(regX.length == 0) return;
@@ -1505,28 +1566,51 @@ public void dataRegionUpdated(double[] regX, float[] regY, double resolution)
 				xmax = newX[newX.length - 1];
 			x = newX;
 			y = newY;
-			fireSignalUpdated(true);
+                        checkSize();
+			return UPDATE_LIMITS;
 		}
 		else
 		{
-			resolutionManager.addRegion(new RegionDescriptor(regX[0], regX[regX.length - 1], resolution));
+                        resolutionManager.addRegion(new RegionDescriptor(regX[0], regX[regX.length - 1], resolution));
 			x = newX;
 			y = newY;
-			fireSignalUpdated(false);
+			return DO_NOT_UPDATE_LIMITS;
 		}
+            }catch(Exception exc)
+            {
+                System.out.println("Exception in Signal.dataRegionUpdated");
+                exc.printStackTrace();
+            }
+            return UPDATE_PENDING;
 	}
 
 	@Override
 	public void dataRegionUpdated(long[] regX, float[] regY, double resolution)
+        {
+            int updateStatus = updateDataRegion(regX, regY, resolution);
+            if(updateStatus == UPDATE_LIMITS)
+            {
+                fireSignalUpdated(true);
+            }
+            else if (updateStatus == DO_NOT_UPDATE_LIMITS)
+            {
+                 fireSignalUpdated(false);
+           }
+       }
+	
+                
+                
+                
+	public synchronized int updateDataRegion(long[] regX, float[] regY, double resolution)
 	{
 		if (regX == null || regX.length == 0)
-			return;
+			return UPDATE_PENDING;
 		if (debug)
 			System.out.println("dataRegionUpdated " + resolutionManager.lowResRegions.size());
 		if (freezeMode == FREEZED_BLOCK) // If zooming in some inner part of the signal
 		{
 			pendingUpdatesV.addElement(new XYData(regX, regY, resolution, true));
-			return;
+			return UPDATE_PENDING;
 		}
 		/*
 		 * if(freezeMode == FREEZED_SCROLL) //If zooming the end of the signal do the
@@ -1550,7 +1634,7 @@ public void dataRegionUpdated(long[] regX, float[] regY, double resolution)
 			for (int i = 0; i < regX.length; i++)
 				x[i] = regX[i];
 			y = regY;
-			fireSignalUpdated(true);
+                        return UPDATE_LIMITS;
 		}
 		else // Data Appended
 		{
@@ -1603,7 +1687,7 @@ else if (freezeMode == NOT_FREEZED)
 				x = newX;
 				xLong = newXLong;
 				y = newY;
-				fireSignalUpdated(true);
+				return UPDATE_LIMITS;
 			}
 			else
 			{
@@ -1611,10 +1695,32 @@ else if (freezeMode == NOT_FREEZED)
 				x = newX;
 				xLong = newXLong;
 				y = newY;
-				fireSignalUpdated(false);
+				return DO_NOT_UPDATE_LIMITS;
 			}
 		}
-	}
+ 	}
+        
+// Management of data reduction in case of append
+        synchronized void checkSize()
+        {
+            if(longXLimits) //On the  fly compression not performed for absolute times
+            {
+                return;
+            }
+            if(x == null || x.length < DIM_THRESHOLD)
+            {
+                return;
+            }
+            double xMin = x[0];
+            double xMax = x[x.length - 1];
+            if(xMin >= xMax) 
+            {
+                return;
+            }
+            mergeRegions();
+        }
+         
+        
 
 	public void decShow()
 	{
@@ -2301,14 +2407,18 @@ public void legendUpdated(String name)
 
 	// reset all region info building a single region with
 	// resolution=NUM_POINTS/(xmax - xmin)
-	public void mergeRegions()
+	public synchronized void mergeRegions()
 	{
 		if (x == null || x.length < 1)
 			return;
-		final double currXMin = x[0];
+                if (x.length < DIM_THRESHOLD) //Do the Job only if it is worth
+                    return;
+                final double currXMin = x[0];
 		final double currXMax = x[x.length - 1];
-		final double currResolution = 3 * NUM_POINTS / (currXMax - currXMin);
-		final double currDelta = (currXMax - currXMin) / (3 * NUM_POINTS);
+		final double currResolution = NUM_POINTS / (currXMax - currXMin);
+		//final double currResolution = 3 * NUM_POINTS / (currXMax - currXMin);
+		//final double currDelta = (currXMax - currXMin) / (3 * NUM_POINTS);
+		final double currDelta = (currXMax - currXMin) / NUM_POINTS;
 		int newPoints = 0;
 		double currX = currXMin - currDelta / 2;
 		int currIdx = 0;
@@ -2833,7 +2943,7 @@ public void setXLimits(double xmin, double xmax, int mode)
 			if (((mode & DO_NOT_UPDATE) == 0)
 					&& (currLower != saved_xmin || currUpper != saved_xmax || (mode & AT_CREATION) == 0))
                         {
-				data.getDataAsync(currLower, currUpper, NUM_POINTS);
+ 				data.getDataAsync(currLower, currUpper, NUM_POINTS);
                         }
 		}
 		// fireSignalUpdated();
diff --git a/java/jscope/src/main/java/mds/wave/WaveInterface.java b/java/jscope/src/main/java/mds/wave/WaveInterface.java
index f9ae001dd5..129fd89b51 100644
--- a/java/jscope/src/main/java/mds/wave/WaveInterface.java
+++ b/java/jscope/src/main/java/mds/wave/WaveInterface.java
@@ -448,7 +448,7 @@ public void Erase()
 		evaluated = null;
 	}
 
-	public synchronized boolean EvaluateOthers()
+	public  boolean EvaluateOthers()
 	{
 		int curr_wave;
 		if (is_image)
@@ -509,7 +509,7 @@ public synchronized boolean EvaluateOthers()
 		return retStatus;
 	}
 
-	public synchronized void EvaluateShot(long shot) throws Exception
+	public  void EvaluateShot(long shot) throws Exception
 	{
 		int curr_wave;
 		if (is_image)
diff --git a/java/jscope/src/main/java/mds/wave/Waveform.java b/java/jscope/src/main/java/mds/wave/Waveform.java
index d23eea7299..284bd7cca9 100644
--- a/java/jscope/src/main/java/mds/wave/Waveform.java
+++ b/java/jscope/src/main/java/mds/wave/Waveform.java
@@ -11,8 +11,10 @@
 
 import javax.swing.BorderFactory;
 import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
 import javax.swing.border.BevelBorder;
 import javax.swing.border.Border;
+import mds.jscope.jScopeMultiWave;
 
 public class Waveform extends JComponent implements SignalListener
 {
@@ -358,7 +360,7 @@ public synchronized void addWaveformListener(WaveformListener l)
 		waveform_listener.addElement(l);
 	}
 
-	synchronized public void appendPaint(Graphics g, Dimension d)
+	 public void appendPaint(Graphics g, Dimension d)
 	{
 		setFont(g);
 		g.setColor(Color.black);
@@ -469,7 +471,25 @@ public void DeselectWave()
 		setBorder(unselect_border);
 	}
 
-	protected synchronized void dispatchWaveformEvent(WaveformEvent e)
+        protected void dispatchWaveformEvent(WaveformEvent e)
+        {
+            class Invoker implements Runnable {
+                WaveformEvent e;
+                public Invoker(WaveformEvent e) 
+                {
+                    this.e = e;
+                }
+                public void run()
+                {
+                    intDispatchWaveformEvent(e);
+                }
+            }
+            SwingUtilities.invokeLater(new Invoker(e));
+	}
+   
+                
+        
+	protected void intDispatchWaveformEvent(WaveformEvent e)
 	{
 		if (e == null || !event_enabled)
 		{
@@ -1462,7 +1482,7 @@ public void paintComponent(Graphics g)
 			sendProfileEvent();
 	}
 
-	synchronized public void PaintImage(Graphics g, Dimension d, int print_mode)
+	 public void PaintImage(Graphics g, Dimension d, int print_mode)
 	{
 		if (frames != null)
 		{
@@ -1482,7 +1502,7 @@ synchronized public void PaintImage(Graphics g, Dimension d, int print_mode)
 		}
 	}
 
-	synchronized protected void PaintSignal(Graphics g, Dimension dim, int print_mode)
+	 protected void PaintSignal(Graphics g, Dimension dim, int print_mode)
 	{
 		Dimension d;
 		String orizLabel = x_label;
@@ -1642,7 +1662,7 @@ public boolean Playing()
 		return is_playing;
 	}
 
-	public synchronized void removeWaveformListener(WaveformListener l)
+	public void removeWaveformListener(WaveformListener l)
 	{
 		if (l == null)
 		{
@@ -2753,7 +2773,7 @@ public void signalUpdated(boolean changeLimits)
 		repaint();
 	}
 
-	synchronized public void StopFrame()
+         public void StopFrame()
 	{
 		if (is_image && is_playing)
 		{
@@ -2809,7 +2829,7 @@ public void Update(float x[], float y[])
 		repaint();
 	}
 
-	synchronized public void Update(Signal s)
+	 public void Update(Signal s)
 	{
 		update_timestamp++;
 		waveform_signal = s;
@@ -2840,7 +2860,7 @@ public void UpdatePoint(double curr_x)
 		UpdatePoint(curr_x, Double.NaN);
 	}
 
-	public synchronized void UpdatePoint(double curr_x, double curr_y)
+	public  void UpdatePoint(double curr_x, double curr_y)
 	{
 		final Dimension d = getWaveSize();
 		if (curr_x == curr_point && !dragging)
diff --git a/java/jscope/src/main/java/mds/wave/WaveformContainer.java b/java/jscope/src/main/java/mds/wave/WaveformContainer.java
index ea9a5e75e9..6fe99d5757 100644
--- a/java/jscope/src/main/java/mds/wave/WaveformContainer.java
+++ b/java/jscope/src/main/java/mds/wave/WaveformContainer.java
@@ -84,7 +84,7 @@ public void AddComponents(Component c[])
 	 *
 	 * @param l the waveform container listener
 	 */
-	public synchronized void addWaveContainerListener(WaveContainerListener l)
+	public  void addWaveContainerListener(WaveContainerListener l)
 	{
 		if (l == null)
 		{
@@ -142,18 +142,6 @@ public void allSameYScale(Waveform curr_w)
 					w.SetYScale(curr_w);
 		}
 	}
-
-	synchronized public void appendUpdateWaveforms()
-	{
-		Waveform w;
-		for (int i = 0; i < getGridComponentCount(); i++)
-		{
-			w = GetWavePanel(i);
-			if (w != null)
-				w.appendUpdate();
-		}
-	}
-
 	@Override
 	public void autoscaleAll()
 	{
@@ -590,7 +578,7 @@ public void RemoveAllSignals()
 	 *
 	 * @param l the waveform container listener
 	 */
-	public synchronized void removeContainerListener(ActionListener l)
+	public void removeContainerListener(ActionListener l)
 	{
 		if (l == null)
 		{
@@ -1009,15 +997,4 @@ public void updatePoints(double x, Waveform curr_w)
 				w.UpdatePoint(x, y);
 		}
 	}
-
-	synchronized public void updateWaveforms()
-	{
-		Waveform w;
-		for (int i = 0; i < getGridComponentCount(); i++)
-		{
-			w = GetWavePanel(i);
-			if (w != null)
-				w.Update();
-		}
-	}
 }
diff --git a/java/mdsobjects/src/main/java/mds/connection/MdsConnection.java b/java/mdsobjects/src/main/java/mds/connection/MdsConnection.java
index 220ac2019d..51caa5da57 100644
--- a/java/mdsobjects/src/main/java/mds/connection/MdsConnection.java
+++ b/java/mdsobjects/src/main/java/mds/connection/MdsConnection.java
@@ -3,7 +3,7 @@
 import java.io.*;
 import java.net.*;
 import java.util.*;
-
+import javax.swing.*;
 public class MdsConnection
 {
 	public static final int DEFAULT_PORT = 8000;
@@ -81,9 +81,23 @@ public void run()
 			if (MdsConnection.this.busy)
 				return;
 			if (eventName != null)
-				dispatchUpdateEvent(eventName);
+                        {
+                            SwingUtilities.invokeLater(new Runnable() {
+                                public void run()
+                                {
+                                    dispatchUpdateEvent(eventName);
+                                }
+                            });
+                        }
 			else if (eventId != -1)
-				dispatchUpdateEvent(eventId);
+                        {
+                            SwingUtilities.invokeLater(new Runnable() {
+                                public void run()
+                                {
+                                    dispatchUpdateEvent(eventId);
+                                }
+                            });
+                        }
 		}
 
 		public void SetEventid(int id)
@@ -236,7 +250,7 @@ public void setUser(String user)
 	public String getProviderUser()
 	{ return (user != null ? user : DEFAULT_USER); }
 
-	public synchronized String getProviderHost()
+	public String getProviderHost()
 	{
 		if (provider == null)
 			return null;
@@ -252,7 +266,7 @@ public synchronized String getProviderHost()
 		return address.trim();
 	}
 
-	public synchronized int getProviderPort() throws NumberFormatException
+	public int getProviderPort() throws NumberFormatException
 	{
 		if (provider == null)
 			return DEFAULT_PORT;
@@ -263,7 +277,7 @@ public synchronized int getProviderPort() throws NumberFormatException
 		return port;
 	}
 
-	public synchronized Descriptor getAnswer() throws IOException
+	public Descriptor getAnswer() throws IOException
 	{
 		final Descriptor out = new Descriptor();
 		final MdsMessage message = receiveThread.GetMessage();
@@ -506,7 +520,7 @@ public synchronized int RemoveEvent(UpdateEventListener l, String eventName)
 		return eventid;
 	}
 
-	public synchronized void dispatchUpdateEvent(int eventid)
+	public void dispatchUpdateEvent(int eventid)
 	{
 		if (hashEventId.containsKey(eventid))
 		{
@@ -514,7 +528,7 @@ public synchronized void dispatchUpdateEvent(int eventid)
 		}
 	}
 
-	public synchronized void dispatchUpdateEvent(String eventName)
+	public void dispatchUpdateEvent(String eventName)
 	{
 		if (hashEventName.containsKey(eventName))
 		{
diff --git a/java/mdsobjects/src/main/java/mds/connection/MdsMessage.java b/java/mdsobjects/src/main/java/mds/connection/MdsMessage.java
index 7e115c51f0..fcf245edf5 100644
--- a/java/mdsobjects/src/main/java/mds/connection/MdsMessage.java
+++ b/java/mdsobjects/src/main/java/mds/connection/MdsMessage.java
@@ -123,7 +123,7 @@ protected short ByteToShortSwap(byte b[], int idx)
 		return (short) ((ch1) + (ch2));
 	}
 
-	synchronized protected void dispatchConnectionEvent(ConnectionEvent e)
+	protected void dispatchConnectionEvent(ConnectionEvent e)
 	{
 		if (connectionListeners != null)
 			for (final ConnectionListener listener : connectionListeners)
@@ -162,7 +162,7 @@ protected final boolean IsRoprand(byte arr[], int idx)
 		return (arr[idx] == 0 && arr[idx + 1] == 0 && arr[idx + 2] == -128 && arr[idx + 3] == 0);
 	}
 
-	protected synchronized void ReadBuf(byte buf[], InputStream dis) throws IOException
+	protected  void ReadBuf(byte buf[], InputStream dis) throws IOException
 	{
 		ConnectionEvent e;
 		int bytes_to_read = buf.length, read_bytes = 0, curr_offset = 0;
diff --git a/java/mdsplus-api/src/main/java/mds/MdsMisc.java b/java/mdsplus-api/src/main/java/mds/MdsMisc.java
index 2c7d88fa6e..bfb4ade0d2 100644
--- a/java/mdsplus-api/src/main/java/mds/MdsMisc.java
+++ b/java/mdsplus-api/src/main/java/mds/MdsMisc.java
@@ -10,6 +10,7 @@
 import mds.data.descriptor.Descriptor;
 import mds.data.descriptor_a.Uint8Array;
 import mds.data.descriptor_s.Float32;
+import mds.data.descriptor_s.Float64;
 import mds.data.descriptor_s.Int32;
 import mds.data.descriptor_s.Int64;
 
@@ -230,6 +231,15 @@ private final byte[] _miscGetXYSignal(final CTX ctx, final String ydata, final S
 		return this.mds.getByteArray(ctx, request);
 	}
 
+	private final byte[] _miscGetXYSignalDoubleLimits(final CTX ctx, final String ydata, final String xdata, final double xmin,
+			final double xmax, final int num_samples) throws MdsException
+	{
+		final Request<Uint8Array> request = new MiscCall<>(Uint8Array.class, "GetXYSignalDoubleLimits:DSC")//
+				.ref(Descriptor.valueOf(ydata)).ref(Descriptor.valueOf(xdata)).ref(new Float64(xmin))
+				.ref(new Float64(xmax)).ref(new Int32(num_samples)).fin();
+		return this.mds.getByteArray(ctx, request);
+	}
+
 	private final byte[] _miscGetXYSignalLongTimes(final CTX ctx, final String ydata, final String xdata,
 			final long xmin, final long xmax, final int num_samples) throws MdsException
 	{
diff --git a/mdsmisc/ScopeUtilities.c b/mdsmisc/ScopeUtilities.c
index 759e999312..3d60028286 100644
--- a/mdsmisc/ScopeUtilities.c
+++ b/mdsmisc/ScopeUtilities.c
@@ -1116,8 +1116,9 @@ static mdsdsc_xd_t *getPackedDsc(mdsdsc_xd_t *retXd)
   return retXd;
 }
 
-EXPORT mdsdsc_xd_t *GetXYSignal(char *inY, char *inX, float *inXMin,
-                                float *inXMax, int *reqNSamples)
+
+EXPORT mdsdsc_xd_t *GetXYSignalDoubleLimits(char *inY, char *inX, double *inXMin,
+                                double *inXMax, int *reqNSamples)
 {
   static EMPTYXD(retXd);
   const size_t len = strlen(inY);
@@ -1127,8 +1128,8 @@ EXPORT mdsdsc_xd_t *GetXYSignal(char *inY, char *inX, float *inXMin,
     return (encodeError("Y data must not be NULL or empty.", __LINE__, &retXd));
   EMPTYXD(yXd);
   EMPTYXD(xXd);
-  mdsdsc_t xMinD = {sizeof(float), DTYPE_FLOAT, CLASS_S, (char *)inXMin};
-  mdsdsc_t xMaxD = {sizeof(float), DTYPE_FLOAT, CLASS_S, (char *)inXMax};
+  mdsdsc_t xMinD = {sizeof(double), DTYPE_DOUBLE, CLASS_S, (char *)inXMin};
+  mdsdsc_t xMaxD = {sizeof(double), DTYPE_DOUBLE, CLASS_S, (char *)inXMax};
   int status;
   {
     mdsdsc_t expY = {len, DTYPE_T, CLASS_S, inY};
@@ -1150,6 +1151,7 @@ EXPORT mdsdsc_xd_t *GetXYSignal(char *inY, char *inX, float *inXMin,
   return getPackedDsc(&retXd);
 }
 
+
 EXPORT mdsdsc_xd_t *GetXYSignalLongTimes(char *inY, char *inX, int64_t *inXMin,
                                          int64_t *inXMax, int *reqNSamples)
 {
diff --git a/mdsmisc/resample.c b/mdsmisc/resample.c
index 809398c662..f451fee3d4 100644
--- a/mdsmisc/resample.c
+++ b/mdsmisc/resample.c
@@ -59,9 +59,9 @@ dsc$descriptor *x);
 #include <mdsdescrip.h>
 #include <mdsshr.h>
 
-extern int TdiData(mdsdsc_t *, ...);
-extern int TdiCvt(mdsdsc_t *, ...);
-extern int TdiDimOf(mdsdsc_t *, ...);
+extern int TdiData();
+extern int TdiCvt();
+extern int TdiDimOf();
 struct descriptor *Resample(struct descriptor *in_sig, struct descriptor *in_x);
 
 EXPORT struct descriptor *resample(struct descriptor *in_sig,
@@ -115,19 +115,19 @@ EXPORT struct descriptor *Resample(struct descriptor *in_sig,
     sig = (struct descriptor_signal *)sig->pointer;
   while (x->dtype == DTYPE_DSC)
     x = (struct descriptor *)x->pointer;
-  return_on_error(TdiData((mdsdsc_t *)sig, &xd1 MDS_END_ARG),
+  return_on_error(TdiData(sig, &xd1 MDS_END_ARG),
                   ((struct descriptor *)&bad_sig_in));
-  return_on_error(TdiCvt((mdsdsc_t *)&xd1, &float_dsc, &sig_y_xd MDS_END_ARG),
+  return_on_error(TdiCvt(&xd1, &float_dsc, &sig_y_xd MDS_END_ARG),
                   (struct descriptor *)&bad_sig_in);
   sig_y = (struct descriptor_a *)sig_y_xd.pointer;
   if (sig_y->class != CLASS_A)
     return (struct descriptor *)&bad_sig_in;
   sig_y_f = (float *)sig_y->pointer;
-  return_on_error(TdiDimOf((mdsdsc_t *)sig, &xd1 MDS_END_ARG),
+  return_on_error(TdiDimOf(sig, &xd1 MDS_END_ARG),
                   (struct descriptor *)&bad_sig_in);
-  return_on_error(TdiData((mdsdsc_t *)&xd1, &xd2 MDS_END_ARG),
+  return_on_error(TdiData(&xd1, &xd2 MDS_END_ARG),
                   (struct descriptor *)&bad_sig_in);
-  return_on_error(TdiCvt((mdsdsc_t *)&xd2, &float_dsc, &sig_x_xd MDS_END_ARG),
+  return_on_error(TdiCvt(&xd2, &float_dsc, &sig_x_xd MDS_END_ARG),
                   (struct descriptor *)&bad_sig_in);
   sig_x = (struct descriptor_a *)sig_x_xd.pointer;
   if (sig_x->class != CLASS_A)
@@ -135,7 +135,7 @@ EXPORT struct descriptor *Resample(struct descriptor *in_sig,
   sig_x_f = (float *)sig_x->pointer;
   return_on_error(TdiData(x, &xd1 MDS_END_ARG),
                   (struct descriptor *)&bad_time_in);
-  return_on_error(TdiCvt((mdsdsc_t *)&xd1, &float_dsc, &new_x_xd MDS_END_ARG),
+  return_on_error(TdiCvt(&xd1, &float_dsc, &new_x_xd MDS_END_ARG),
                   (struct descriptor *)&bad_time_in);
   new_x = (struct descriptor_a *)new_x_xd.pointer;
   if (new_x->class != CLASS_A)
diff --git a/mdsmisc/step_resample.c b/mdsmisc/step_resample.c
index 408460f6aa..377019c996 100644
--- a/mdsmisc/step_resample.c
+++ b/mdsmisc/step_resample.c
@@ -59,10 +59,10 @@ struct descriptor_xd *STEP_RESAMPLE(struct descriptor *sig,struct descriptor
 #include <mdsdescrip.h>
 #include <mdsshr.h>
 
-extern int TdiData(mdsdsc_t *, ...);
-extern int TdiByte(mdsdsc_t *, ...);
-extern int TdiDimOf(mdsdsc_t *, ...);
-extern int TdiCvt(mdsdsc_t *, ...);
+extern int TdiData();
+extern int TdiByte();
+extern int TdiDimOf();
+extern int TdiCvt();
 
 EXPORT struct descriptor *StepResample(struct descriptor *in_sig,
                                        struct descriptor *in_x)
@@ -104,21 +104,21 @@ EXPORT struct descriptor *StepResample(struct descriptor *in_sig,
     sig = (struct descriptor_signal *)sig->pointer;
   while (x->dtype == DTYPE_DSC)
     x = (struct descriptor *)x->pointer;
-  return_on_error(TdiData((mdsdsc_t *)sig, &xd1 MDS_END_ARG));
-  return_on_error(TdiByte((mdsdsc_t *)&xd1, &sig_y_xd MDS_END_ARG));
+  return_on_error(TdiData(sig, &xd1 MDS_END_ARG));
+  return_on_error(TdiByte(&xd1, &sig_y_xd MDS_END_ARG));
   sig_y = (struct descriptor_a *)sig_y_xd.pointer;
   if (sig_y->class != CLASS_A)
     return 0;
   sig_y_b = sig_y->pointer;
-  return_on_error(TdiDimOf((mdsdsc_t *)sig, &xd1 MDS_END_ARG));
-  return_on_error(TdiData((mdsdsc_t *)&xd1, &xd2 MDS_END_ARG));
-  return_on_error(TdiCvt((mdsdsc_t *)&xd2, &float_dsc, &sig_x_xd MDS_END_ARG));
+  return_on_error(TdiDimOf(sig, &xd1 MDS_END_ARG));
+  return_on_error(TdiData(&xd1, &xd2 MDS_END_ARG));
+  return_on_error(TdiCvt(&xd2, &float_dsc, &sig_x_xd MDS_END_ARG));
   sig_x = (struct descriptor_a *)sig_x_xd.pointer;
   if (sig_x->class != CLASS_A)
     return 0;
   sig_x_f = (float *)sig_x->pointer;
   return_on_error(TdiData(x, &xd1 MDS_END_ARG));
-  return_on_error(TdiCvt((mdsdsc_t *)&xd1, &float_dsc, &new_x_xd MDS_END_ARG));
+  return_on_error(TdiCvt(&xd1, &float_dsc, &new_x_xd MDS_END_ARG));
   new_x = (struct descriptor_a *)new_x_xd.pointer;
   if (new_x->class != CLASS_A)
     return 0;


Reviews:
user: login: heidthecamp
body: I have a few questions and comments but mostly this looks good to me. 
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T17:41:16Z
user: login: GabrieleManduchi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T11:41:20Z
user: login: GabrieleManduchi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T11:42:23Z
user: login: GabrieleManduchi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T11:47:29Z
user: login: GabrieleManduchi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T11:51:37Z
user: login: GabrieleManduchi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T11:52:11Z
user: login: GabrieleManduchi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T11:56:01Z
user: login: GabrieleManduchi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T12:10:34Z
user: login: GabrieleManduchi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T12:16:57Z
user: login: heidthecamp
body: Thank you for the updates looks good to me.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T14:40:17Z

Review comments:
diff_hunk: @@ -795,17 +819,19 @@ public void getDataAsync(double lowerBound, double upperBound, int numPoints)
 		@Override
 		public int getNumDimension() throws IOException
 		{
-			if (numDimensions != UNKNOWN)
+                   			if (numDimensions != UNKNOWN)
path: java/jscope/src/main/java/mds/provider/MdsDataProvider.java
user: login: heidthecamp
body: I think this is a formatting mistake
created_at: 2025-05-07T14:06:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -651,11 +650,30 @@ public XYData getData(double xmin, double xmax, int numPoints, boolean isLong) t
 				if (numPoints == Integer.MAX_VALUE)
 					throw new Exception("Use Old Method for getting data");
 				if (isLong)
-//                      retData = GetByteArray(setTimeContext+" MdsMisc->GetXYSignalLongTimes:DSC", args);
 					retData = GetByteArray(" MdsMisc->GetXYSignalLongTimes:DSC", args);
 				else
-//                      retData = GetByteArray(setTimeContext+" MdsMisc->GetXYSignal:DSC", args);
-					retData = GetByteArray(" MdsMisc->GetXYSignal:DSC", args);
+                                {
+                                    try {
+ 					retData = GetByteArray(" MdsMisc->GetXYSignalDoubleLimits:DSC", args);
+                                    }catch(Exception exc)
+                                    {
+                                        //Try old method in case the mdsip server is not up-to-date
path: java/jscope/src/main/java/mds/provider/MdsDataProvider.java
user: login: heidthecamp
body: Good call out! I was confused why we were attempting to call the old method but it makes sense that the server may not have the same be on the same version. 
created_at: 2025-05-07T14:29:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1116,8 +1116,9 @@ static mdsdsc_xd_t *getPackedDsc(mdsdsc_xd_t *retXd)
   return retXd;
 }
 
-EXPORT mdsdsc_xd_t *GetXYSignal(char *inY, char *inX, float *inXMin,
path: mdsmisc/ScopeUtilities.c
user: login: heidthecamp
body: Can you run a find all and make sure we're not missing any references? It looks like there is a reference to it here: https://github.com/MDSplus/mdsplus/blob/alpha/java/mdsplus-api/src/main/java/mds/MdsMisc.java#L227

created_at: 2025-05-07T14:35:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1009,8 +1009,8 @@ public void updatePoints(double x, Waveform curr_w)
 				w.UpdatePoint(x, y);
 		}
 	}
-
-	synchronized public void updateWaveforms()
+/*
path: java/jscope/src/main/java/mds/wave/WaveformContainer.java
user: login: heidthecamp
body: Should this be removed entirely? If not I think we should add `TODO:` as the first line of the comment for future find-ability. 
created_at: 2025-05-07T14:39:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -142,8 +142,8 @@ public void allSameYScale(Waveform curr_w)
 					w.SetYScale(curr_w);
 		}
 	}
-
-	synchronized public void appendUpdateWaveforms()
+/*
path: java/jscope/src/main/java/mds/wave/WaveformContainer.java
user: login: heidthecamp
body: Should this be removed entirely? If not I think we should add TODO: as the first line of the comment for future find-ability.
created_at: 2025-05-07T14:39:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -957,7 +957,7 @@ public synchronized boolean refreshOnEvent() throws Exception
 			{
 				if (!signals[sigIdx].supportsStreaming() || !signals[sigIdx].updateSignal())
 					return false;
-				signals[sigIdx].mergeRegions();
path: java/jscope/src/main/java/mds/jscope/MdsWaveInterface.java
user: login: heidthecamp
body: Why are we removing mergeRegions? If we're removing it can we delete the line rather than just comment it?
created_at: 2025-05-07T14:53:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -957,7 +957,7 @@ public synchronized boolean refreshOnEvent() throws Exception
 			{
 				if (!signals[sigIdx].supportsStreaming() || !signals[sigIdx].updateSignal())
 					return false;
-				signals[sigIdx].mergeRegions();
path: java/jscope/src/main/java/mds/jscope/MdsWaveInterface.java
user: login: heidthecamp
body: It also looks like this is the only place, in our code, that mergeRegions is used. 
created_at: 2025-05-07T14:55:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,8 +125,11 @@ private int BuildGrid(double val[], int mode, double xmax, double ymax, double x
 		curr = (long) (curr_min / step) * step;
 		if (curr > curr_min)
 			curr -= (long) ((curr - curr_min) / step) * step;
-		while (curr >= curr_min)
+                int maxSteps = 1000;
path: java/jscope/src/main/java/mds/wave/Grid.java
user: login: heidthecamp
body: Would you mind leaving a comment on why maxSteps is 1000?
created_at: 2025-05-07T15:07:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -53,7 +56,13 @@ void addRegion(RegionDescriptor newReg)
 			// Skip disjoint regions with lower bounds
 			if (newReg.upperBound < newReg.lowerBound)
 			{
-				System.err.println("INTERNAL ERROR: LOWER BOUND > UPPER BOUND!!!!!");
+				System.err.println("INTERNAL ERROR : LOWER BOUND "+ newReg.lowerBound +" > UPPER BOUND ("+newReg.upperBound+")");
+                                try {
+                                    throw(new Exception());
+                                }catch(Exception exc)
+                                {
+                                    exc.printStackTrace();
+                                }
path: java/jscope/src/main/java/mds/wave/Signal.java
user: login: heidthecamp
body: Why are we trying to throw an exception? Would this not just hide errors?
created_at: 2025-05-07T15:10:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -795,17 +819,19 @@ public void getDataAsync(double lowerBound, double upperBound, int numPoints)
 		@Override
 		public int getNumDimension() throws IOException
 		{
-			if (numDimensions != UNKNOWN)
+                   			if (numDimensions != UNKNOWN)
path: java/jscope/src/main/java/mds/provider/MdsDataProvider.java
user: login: GabrieleManduchi
body: True, fixed
created_at: 2025-05-08T11:41:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -651,11 +650,30 @@ public XYData getData(double xmin, double xmax, int numPoints, boolean isLong) t
 				if (numPoints == Integer.MAX_VALUE)
 					throw new Exception("Use Old Method for getting data");
 				if (isLong)
-//                      retData = GetByteArray(setTimeContext+" MdsMisc->GetXYSignalLongTimes:DSC", args);
 					retData = GetByteArray(" MdsMisc->GetXYSignalLongTimes:DSC", args);
 				else
-//                      retData = GetByteArray(setTimeContext+" MdsMisc->GetXYSignal:DSC", args);
-					retData = GetByteArray(" MdsMisc->GetXYSignal:DSC", args);
+                                {
+                                    try {
+ 					retData = GetByteArray(" MdsMisc->GetXYSignalDoubleLimits:DSC", args);
+                                    }catch(Exception exc)
+                                    {
+                                        //Try old method in case the mdsip server is not up-to-date
path: java/jscope/src/main/java/mds/provider/MdsDataProvider.java
user: login: GabrieleManduchi
body: This happens e.g. when updating jScope on a client node, still retaining the old mdsip on the (less dynamic) server node.
created_at: 2025-05-08T11:42:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1116,8 +1116,9 @@ static mdsdsc_xd_t *getPackedDsc(mdsdsc_xd_t *retXd)
   return retXd;
 }
 
-EXPORT mdsdsc_xd_t *GetXYSignal(char *inY, char *inX, float *inXMin,
path: mdsmisc/ScopeUtilities.c
user: login: GabrieleManduchi
body: mdsplus-api is a separate library. Honestly, I was unaware of it, and I am not sure what its purpose is. In any case, for consistency, I will add there _miscGetXYSignalDoubleLimits()
created_at: 2025-05-08T11:47:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1009,8 +1009,8 @@ public void updatePoints(double x, Waveform curr_w)
 				w.UpdatePoint(x, y);
 		}
 	}
-
-	synchronized public void updateWaveforms()
+/*
path: java/jscope/src/main/java/mds/wave/WaveformContainer.java
user: login: GabrieleManduchi
body: Yes, removed.
created_at: 2025-05-08T11:51:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -142,8 +142,8 @@ public void allSameYScale(Waveform curr_w)
 					w.SetYScale(curr_w);
 		}
 	}
-
-	synchronized public void appendUpdateWaveforms()
+/*
path: java/jscope/src/main/java/mds/wave/WaveformContainer.java
user: login: GabrieleManduchi
body: removed also this one
created_at: 2025-05-08T11:52:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -957,7 +957,7 @@ public synchronized boolean refreshOnEvent() throws Exception
 			{
 				if (!signals[sigIdx].supportsStreaming() || !signals[sigIdx].updateSignal())
 					return false;
-				signals[sigIdx].mergeRegions();
path: java/jscope/src/main/java/mds/jscope/MdsWaveInterface.java
user: login: GabrieleManduchi
body: Right, the way regions (i.e. different sections of the signal at different resolutions) are handled has been changed and that method makes no sense now. Removed the commeneted line.
created_at: 2025-05-08T11:56:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -53,7 +56,13 @@ void addRegion(RegionDescriptor newReg)
 			// Skip disjoint regions with lower bounds
 			if (newReg.upperBound < newReg.lowerBound)
 			{
-				System.err.println("INTERNAL ERROR: LOWER BOUND > UPPER BOUND!!!!!");
+				System.err.println("INTERNAL ERROR : LOWER BOUND "+ newReg.lowerBound +" > UPPER BOUND ("+newReg.upperBound+")");
+                                try {
+                                    throw(new Exception());
+                                }catch(Exception exc)
+                                {
+                                    exc.printStackTrace();
+                                }
path: java/jscope/src/main/java/mds/wave/Signal.java
user: login: GabrieleManduchi
body: This internal error sometimes (very rarely and under particular circumstances) arises due to approximation errors in the data packaging process at the mdsip server side. Normally it does not harm, and previously, there was only the printed message INTERNAL ERROR : LOWER BOUND .... I have added the printStackTrace() call in order to rely on more information when this error occurs and be able to better diagnose it in the future. 
created_at: 2025-05-08T12:10:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,8 +125,11 @@ private int BuildGrid(double val[], int mode, double xmax, double ymax, double x
 		curr = (long) (curr_min / step) * step;
 		if (curr > curr_min)
 			curr -= (long) ((curr - curr_min) / step) * step;
-		while (curr >= curr_min)
+                int maxSteps = 1000;
path: java/jscope/src/main/java/mds/wave/Grid.java
user: login: GabrieleManduchi
body: Right, it is ugly. Now the constant MAX_STEPS = 1000 has been defined. (i.e., the maximum number of steps in the tick selection algorithm) 
created_at: 2025-05-08T12:16:57Z
author_association: CONTRIBUTOR

PR comments:
user: login: GabrieleManduchi
created_at: 2025-05-05T13:39:15Z
body: forgot to say.....the new jScope version is also compatible with older mdsip servers that do not implement GetXYSignalDoulbeLimits(). Of course in that case the problem remains (it happens only for very high sampling frequencies)
author_association: CONTRIBUTOR
user: login: GabrieleManduchi
created_at: 2025-05-08T12:19:41Z
body: retest this please
author_association: CONTRIBUTOR
user: login: GabrieleManduchi
created_at: 2025-05-08T13:01:51Z
body: retest this please
author_association: CONTRIBUTOR
user: login: GabrieleManduchi
created_at: 2025-05-08T13:06:19Z
body: For some reason jenkins refuses to build, no apparent reason....................
author_association: CONTRIBUTOR
user: login: heidthecamp
created_at: 2025-05-08T13:26:39Z
body: Jenkins appears to be down currently. It seems to be all branches since yesterday. We intend on looking into this further today.
author_association: CONTRIBUTOR
user: login: heidthecamp
created_at: 2025-05-08T14:14:36Z
body: retest this please
author_association: CONTRIBUTOR
user: login: heidthecamp
created_at: 2025-05-09T14:27:31Z
body: @GabrieleManduchi, before I approve do you have any recommendations on how to test this? 
author_association: CONTRIBUTOR
user: login: GabrieleManduchi
created_at: 2025-05-09T14:35:21Z
body: Being a user interface, it is hard to test in an automated way. In any case, before issuing the pull request, I gave it to our users, and in three weeks, I did not get complaints......
author_association: CONTRIBUTOR