Bug 507092 - Eclipse fails to start: "An internal error occurred during:
"Initializing workspace."

Fixes multiple possible race conditions during initialization of
instance location uncovered by the change in ResourcesPlugin
initialization via commit 8d90fb030df310a974aae5d27d0bc2610c1a14ad. 

The original issue from bug 507092 is fixed in
Activator.getInstanceLocation(), see 507092 comment 27. The change in
MetaDataKeeper makes sure every thread uses same DataArea instance, and
the change in DataArea.assertLocationInitialized() makes sure the
critical file I/O operations on the metadata folder aren't executed in
parallel by multiple threads.

Change-Id: I4ce3ec522b9ef1be41143d52dc440668a958fbcd
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
index 5b62860..e872f8a 100644
--- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
@@ -68,6 +68,15 @@
 	public void start(BundleContext context) throws Exception {
 		bundleContext = context;
 		singleton = this;
+
+		installLocationTracker = openServiceTracker(Location.INSTALL_FILTER);
+		instanceLocationTracker = openServiceTracker(Location.INSTANCE_FILTER);
+		configLocationTracker = openServiceTracker(Location.CONFIGURATION_FILTER);
+		bundleTracker = openServiceTracker(PackageAdmin.class);
+		debugTracker = openServiceTracker(DebugOptions.class);
+		logTracker = openServiceTracker(FrameworkLog.class);
+		localizationTracker = openServiceTracker(BundleLocalization.class);
+
 		RuntimeLog.setLogWriter(getPlatformWriter(context));
 		Dictionary<String, Object> urlProperties = new Hashtable<>();
 		urlProperties.put("protocol", "platform"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -99,16 +108,6 @@
 	 * Return the configuration location service, if available.
 	 */
 	public Location getConfigurationLocation() {
-		if (configLocationTracker == null) {
-			Filter filter = null;
-			try {
-				filter = bundleContext.createFilter(Location.CONFIGURATION_FILTER);
-			} catch (InvalidSyntaxException e) {
-				// should not happen
-			}
-			configLocationTracker = new ServiceTracker<>(bundleContext, filter, null);
-			configLocationTracker.open();
-		}
 		return configLocationTracker.getService();
 	}
 
@@ -116,10 +115,6 @@
 	 * Return the debug options service, if available.
 	 */
 	public DebugOptions getDebugOptions() {
-		if (debugTracker == null) {
-			debugTracker = new ServiceTracker<>(bundleContext, DebugOptions.class.getName(), null);
-			debugTracker.open();
-		}
 		return debugTracker.getService();
 	}
 
@@ -127,10 +122,6 @@
 	 * Return the framework log service, if available.
 	 */
 	public FrameworkLog getFrameworkLog() {
-		if (logTracker == null) {
-			logTracker = new ServiceTracker<>(bundleContext, FrameworkLog.class.getName(), null);
-			logTracker.open();
-		}
 		return logTracker.getService();
 	}
 
@@ -138,16 +129,6 @@
 	 * Return the instance location service, if available.
 	 */
 	public Location getInstanceLocation() {
-		if (instanceLocationTracker == null) {
-			Filter filter = null;
-			try {
-				filter = bundleContext.createFilter(Location.INSTANCE_FILTER);
-			} catch (InvalidSyntaxException e) {
-				// ignore this.  It should never happen as we have tested the above format.
-			}
-			instanceLocationTracker = new ServiceTracker<>(bundleContext, filter, null);
-			instanceLocationTracker.open();
-		}
 		return instanceLocationTracker.getService();
 	}
 
@@ -176,10 +157,6 @@
 	 * Return the package admin service, if available.
 	 */
 	private PackageAdmin getBundleAdmin() {
-		if (bundleTracker == null) {
-			bundleTracker = new ServiceTracker<>(getContext(), PackageAdmin.class.getName(), null);
-			bundleTracker.open();
-		}
 		return bundleTracker.getService();
 	}
 
@@ -197,19 +174,22 @@
 	 * Return the install location service if available.
 	 */
 	public Location getInstallLocation() {
-		if (installLocationTracker == null) {
-			Filter filter = null;
-			try {
-				filter = bundleContext.createFilter(Location.INSTALL_FILTER);
-			} catch (InvalidSyntaxException e) {
-				// should not happen
-			}
-			installLocationTracker = new ServiceTracker<>(bundleContext, filter, null);
-			installLocationTracker.open();
-		}
 		return installLocationTracker.getService();
 	}
 
+	private <T> ServiceTracker<Object, T> openServiceTracker(String filterString) throws InvalidSyntaxException {
+		Filter filter = bundleContext.createFilter(filterString);
+		ServiceTracker<Object, T> tracker = new ServiceTracker<>(bundleContext, filter, null);
+		tracker.open();
+		return tracker;
+	}
+
+	private <T> ServiceTracker<Object, T> openServiceTracker(Class<?> clazz) {
+		ServiceTracker<Object, T> tracker = new ServiceTracker<>(bundleContext, clazz.getName(), null);
+		tracker.open();
+		return tracker;
+	}
+
 	/**
 	 * Returns the bundle id of the bundle that contains the provided object, or
 	 * <code>null</code> if the bundle could not be determined.
@@ -233,12 +213,7 @@
 	 */
 	public ResourceBundle getLocalization(Bundle bundle, String locale) throws MissingResourceException {
 		if (localizationTracker == null) {
-			BundleContext context = Activator.getContext();
-			if (context == null) {
-				throw new MissingResourceException(CommonMessages.activator_resourceBundleNotStarted, bundle.getSymbolicName(), ""); //$NON-NLS-1$
-			}
-			localizationTracker = new ServiceTracker<>(context, BundleLocalization.class.getName(), null);
-			localizationTracker.open();
+			throw new MissingResourceException(CommonMessages.activator_resourceBundleNotStarted, bundle.getSymbolicName(), ""); //$NON-NLS-1$
 		}
 		BundleLocalization location = localizationTracker.getService();
 		ResourceBundle result = null;
@@ -262,31 +237,24 @@
 		}
 		if (installLocationTracker != null) {
 			installLocationTracker.close();
-			installLocationTracker = null;
 		}
 		if (configLocationTracker != null) {
 			configLocationTracker.close();
-			configLocationTracker = null;
 		}
 		if (bundleTracker != null) {
 			bundleTracker.close();
-			bundleTracker = null;
 		}
 		if (debugTracker != null) {
 			debugTracker.close();
-			debugTracker = null;
 		}
 		if (logTracker != null) {
 			logTracker.close();
-			logTracker = null;
 		}
 		if (instanceLocationTracker != null) {
 			instanceLocationTracker.close();
-			instanceLocationTracker = null;
 		}
 		if (localizationTracker != null) {
 			localizationTracker.close();
-			localizationTracker = null;
 		}
 		if (debugRegistration != null) {
 			debugRegistration.unregister();
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/DataArea.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/DataArea.java
index 66d9fee..3db52a1 100644
--- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/DataArea.java
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/DataArea.java
@@ -39,7 +39,7 @@
 	private IPath location; //The location of the instance data
 	private boolean initialized = false;
 
-	protected void assertLocationInitialized() throws IllegalStateException {
+	protected synchronized void assertLocationInitialized() throws IllegalStateException {
 		if (location != null && initialized)
 			return;
 		Activator activator = Activator.getDefault();
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/MetaDataKeeper.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/MetaDataKeeper.java
index dac414a..db99ba0 100644
--- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/MetaDataKeeper.java
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/MetaDataKeeper.java
@@ -10,8 +10,6 @@
  *******************************************************************************/
 package org.eclipse.core.internal.runtime;
 
-import org.eclipse.core.internal.runtime.DataArea;
-
 /**
  * The class contains a set of utilities working platform metadata area.
  * This class can only be used if OSGi plugin is available.
@@ -26,8 +24,9 @@
 	/**
 	 * Returns the object which defines the location and organization
 	 * of the platform's meta area.
+	 * @return non null
 	 */
-	public static DataArea getMetaArea() {
+	public static synchronized DataArea getMetaArea() {
 		if (metaArea != null)
 			return metaArea;