Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 165769 Details for
Bug 308120
ModelManagerImpl's yieldRule() use still susceptible to deadlock
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
ILock + timeout preference patch
sse.yield3.patch (text/plain), 12.37 KB, created by
Min Idzelis
on 2010-04-22 10:23:34 EDT
(
hide
)
Description:
ILock + timeout preference patch
Filename:
MIME Type:
Creator:
Min Idzelis
Created:
2010-04-22 10:23:34 EDT
Size:
12.37 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.wst.sse.core >Index: src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java,v >retrieving revision 1.42 >diff -u -r1.42 ModelManagerImpl.java >--- src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java 13 Apr 2010 19:42:18 -0000 1.42 >+++ src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java 22 Apr 2010 14:21:22 -0000 >@@ -41,6 +41,7 @@ > import org.eclipse.core.runtime.IPath; > import org.eclipse.core.runtime.IStatus; > import org.eclipse.core.runtime.NullProgressMonitor; >+import org.eclipse.core.runtime.OperationCanceledException; > import org.eclipse.core.runtime.Path; > import org.eclipse.core.runtime.Platform; > import org.eclipse.core.runtime.QualifiedName; >@@ -97,81 +98,88 @@ > */ > public class ModelManagerImpl implements IModelManager { > >- private static long WAIT_INTERVAL_MS = 500; >+ >+ > static class ReadEditType { > ReadEditType(String type) { > } > } > >- /** >- * A Data class to track our shared objects >- */ >- static class SharedObject { >+ class SharedObject { > int referenceCountForEdit; > int referenceCountForRead; >- IStructuredModel theSharedModel; >+ volatile IStructuredModel theSharedModel; >+ final ILock LOAD_LOCK = Job.getJobManager().newLock(); > volatile boolean initializing = true; > volatile boolean doWait = true; >- >- SharedObject(IStructuredModel sharedModel) { >- theSharedModel = sharedModel; >- referenceCountForRead = 0; >- referenceCountForEdit = 0; >+ // The field 'id' is only meant for debug >+ volatile String id; >+ >+ SharedObject(String id) { >+ this.id=id; >+ // be aware, this lock will leak and cause the deadlock detector to be horrible if we never release it >+ LOAD_LOCK.acquire(); > } >- >+ > /** >- * Waits until this shared object has been attempted to be loaded. >- * The load is "attempted" because not all loads result in a model. >- * However, upon leaving this method, theShareModel variable >- * is up-to-date. >+ * Waits until this shared object has been attempted to be loaded. The >+ * load is "attempted" because not all loads result in a model. However, >+ * upon leaving this method, theShareModel variable is up-to-date. > */ > public void waitForLoadAttempt() { >+ final boolean allowInterrupt = PrefUtil.ALLOW_INTERRUPT_WAITING_THREAD; >+ final long timeLimit = (PrefUtil.WAIT_DELAY==0) ? Long.MAX_VALUE : PrefUtil.now() + PrefUtil.WAIT_DELAY; >+ final Job current = Job.getJobManager().currentJob(); > boolean interrupted = false; > try { >- // if we have a rule, then use a polling system with >- // short-circuit, otherwise use wait/notify >- if (Job.getJobManager().currentRule() != null) { >- while (initializing) { >- Job.getJobManager().currentJob().yieldRule(null); >- synchronized (this) { >- if (initializing) { >- try { >- wait(WAIT_INTERVAL_MS); >- } >- catch (InterruptedException e) { >- interrupted = true; >- } >- } >- } >+ while (initializing) { >+ if (current!=null) { >+ current.yieldRule(null); > } >- } >- else { >- synchronized (this) { >- while (initializing) { >- try { >- wait(); >- } >- catch (InterruptedException e) { >- interrupted = true; >- } >+ try { >+ loop(); >+ } catch (InterruptedException e) { >+ if (allowInterrupt) { >+ throw new OperationCanceledException("Waiting thread interrupted while waiting for model id: "+id + " to load"); >+ } else { >+ interrupted=true; > } > } >+ if (PrefUtil.now() >= timeLimit ) >+ throw new OperationCanceledException("Waiting thread timeout exceeded while waiting for model id: "+id + " to load"); > } > } > finally { >- if (interrupted) >+ if (interrupted) { > Thread.currentThread().interrupt(); >+ } > } > } >- >+ >+ private void loop() throws InterruptedException { >+ if (initializing) { >+ if (LOAD_LOCK.acquire(PrefUtil.WAIT_INTERVAL_MS)) { >+ // if we got the lock, but initializing is still not true the deadlock detector gave us >+ // the lock and caused reentrancy into this critical section. This is invalid and the >+ // sign of a cyclical load attempt. In this case, we through an >+ // OperationCanceledException in lew of entering a spin-loop. >+ if (initializing) { >+ LOAD_LOCK.release(); >+ throw new OperationCanceledException("Aborted cyclic load attempt for model with id: "+ id ); >+ } else { >+ LOAD_LOCK.release(); >+ } >+ } >+ } >+ } >+ > /** >- * Flags this model as loaded. All waiting methods on >- * {@link #waitForLoadAttempt()} will proceed after this >- * method returns. >+ * Flags this model as loaded. All waiting methods on >+ * {@link #waitForLoadAttempt()} will proceed after this method returns. > */ >- public synchronized void setLoaded() { >+ public void setLoaded() { > initializing = false; >- notifyAll(); >+ LOAD_LOCK.release(); > } > } > >@@ -239,7 +247,7 @@ > SharedObject testObject = (SharedObject) fManagedObjects.get(id); > if (testObject==null) { > // null means it's been disposed, we need to do the work to reload it. >- sharedObject = new SharedObject(null); >+ sharedObject = new SharedObject(id); > fManagedObjects.put(id, sharedObject); > SYNC.release(); > _doCommonCreateModel(file, id, handler, resolver, rwType, encodingRule, >@@ -350,7 +358,7 @@ > SharedObject testObject = (SharedObject) fManagedObjects.get(id); > if (testObject==null) { > // it was removed ,so lets create it >- sharedObject = new SharedObject(null); >+ sharedObject = new SharedObject(id); > fManagedObjects.put(id, sharedObject); > SYNC.release(); > _doCommonCreateModel(inputStream, id, handler, resolver, rwType, >@@ -491,7 +499,7 @@ > SharedObject testObject = (SharedObject) fManagedObjects.get(id); > if (testObject==null) { > // it was removed ,so lets create it >- sharedObject = new SharedObject(null); >+ sharedObject = new SharedObject(id); > fManagedObjects.put(id, sharedObject); > > SYNC.release(); >@@ -567,7 +575,7 @@ > throw new ResourceInUse(); > } > >- sharedObject = new SharedObject(null); >+ sharedObject = new SharedObject(id); > fManagedObjects.put(id, sharedObject); > > } finally { >@@ -612,7 +620,7 @@ > SYNC.acquire(); > SharedObject testObject = (SharedObject) fManagedObjects.get(id); > if (testObject==null) { >- sharedObject = new SharedObject(null); >+ sharedObject = new SharedObject(id); > fManagedObjects.put(id, sharedObject); > SYNC.release(); > synchronized(sharedObject) { >@@ -830,7 +838,7 @@ > if (sharedObject != null) { > throw new ResourceInUse(); > } >- sharedObject = new SharedObject(null); >+ sharedObject = new SharedObject(newId); > fManagedObjects.put(newId,sharedObject); > } finally { > SYNC.release(); >Index: src/org/eclipse/wst/sse/core/internal/model/PrefUtil.java >=================================================================== >RCS file: src/org/eclipse/wst/sse/core/internal/model/PrefUtil.java >diff -N src/org/eclipse/wst/sse/core/internal/model/PrefUtil.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/wst/sse/core/internal/model/PrefUtil.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,135 @@ >+package org.eclipse.wst.sse.core.internal.model; >+ >+import org.eclipse.core.runtime.Platform; >+import org.eclipse.core.runtime.preferences.ConfigurationScope; >+import org.eclipse.core.runtime.preferences.IEclipsePreferences; >+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; >+import org.eclipse.core.runtime.preferences.IPreferencesService; >+import org.eclipse.core.runtime.preferences.InstanceScope; >+import org.eclipse.osgi.util.NLS; >+import org.eclipse.wst.sse.core.internal.SSECorePlugin; >+import org.osgi.service.prefs.Preferences; >+ >+public class PrefUtil { >+ >+ static long WAIT_INTERVAL_MS = 500; >+ static int WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad"); >+ static boolean ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad"); >+ >+ /** Base of millisecond timings, to avoid wrapping */ >+ private static final long MILLI_ORIGIN = System.currentTimeMillis(); >+ >+ /** >+ * Returns millisecond time offset by origin >+ */ >+ static final long now() { >+ return System.currentTimeMillis() - MILLI_ORIGIN; >+ } >+ >+ private static IEclipsePreferences.IPreferenceChangeListener LISTENER; >+ static { >+ InstanceScope scope = new InstanceScope(); >+ IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID); >+ LISTENER = new IEclipsePreferences.IPreferenceChangeListener() { >+ >+ public void preferenceChange(PreferenceChangeEvent event) { >+ >+ if ("modelmanager.maxWaitDuringConcurrentLoad".equals(event.getKey())) { >+ WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad"); >+ } >+ else if ("modelmanager.allowInterruptsDuringConcurrentLoad".equals(event.getKey())) { >+ ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad"); >+ } >+ } >+ }; >+ instancePrefs.addPreferenceChangeListener(LISTENER); >+ } >+ >+ private static String getProperty(String property) { >+ // Importance order is: >+ // default-default < instanceScope < configurationScope < systemProperty >+ // < envVar >+ String value = null; >+ >+ if (value == null) { >+ value = System.getenv(property); >+ } >+ if (value == null) { >+ value = System.getProperty(property); >+ } >+ if (value == null) { >+ IPreferencesService preferencesService = Platform.getPreferencesService(); >+ >+ String key = property; >+ if (property != null && property.startsWith(SSECorePlugin.ID)) { >+ // +1, include the "." >+ key = property.substring(SSECorePlugin.ID.length() + 1, property.length()); >+ } >+ InstanceScope instance = new InstanceScope(); >+ ConfigurationScope config = new ConfigurationScope(); >+ >+ Preferences instanceNode = instance.getNode(SSECorePlugin.ID); >+ Preferences configNode = config.getNode(SSECorePlugin.ID); >+ value = preferencesService.get(key, getDefault(property), new Preferences[]{configNode,instanceNode}); >+ } >+ >+ return value; >+ } >+ >+ private static String getDefault(String property) { >+ // this is the "default-default" >+ if ("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad".equals(property)) { >+ return "0"; >+ } >+ else if ("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad".equals(property)) { >+ return "false"; >+ } >+ return null; >+ } >+ >+ private static boolean getBoolean(String key) { >+ String property = getProperty(key); >+ // if (property != null) { >+ // System.out.println("Tweak: " + key + "=" + Boolean.parseBoolean(property)); //$NON-NLS-1$ //$NON-NLS-2$ >+ // } >+ return (property != null ? Boolean.valueOf(property) : Boolean.valueOf(getDefault(key))) >+ .booleanValue(); >+ } >+ >+ private static int getInt(String key) { >+ String property = getProperty(key); >+ int size = 0; >+ if (property != null) { >+ try { >+ size = Integer.parseInt(property); >+ // System.out.println("Tweak: " + key + "=" + size); //$NON-NLS-1$ //$NON-NLS-2$ >+ } >+ catch (NumberFormatException e) { >+ size = getDefaultInt(key, property, size); >+ } >+ } >+ else { >+ size = getDefaultInt(key, property, size); >+ } >+ return size; >+ } >+ >+ private static int getDefaultInt(String key, String property, int size) { >+ // ignored >+ try { >+ size = Integer.parseInt(getDefault(key)); >+ } >+ catch (NumberFormatException e1) { >+ handleIntParseException(key, property, e1); >+ size = 0; >+ } >+ return size; >+ } >+ >+ private static void handleIntParseException(String key, String property, NumberFormatException e1) { >+ Exception n = new Exception(NLS.bind( >+ "Exception during parse of default value for key ''{0}'' value was ''{1}''. Using 0 instead", //$NON-NLS-1$ >+ key, property), e1); >+ n.printStackTrace(); >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
min123
:
review?
Actions:
View
|
Diff
Attachments on
bug 308120
:
163842
| 165769