|
Lines 41-46
Link Here
|
| 41 |
import org.eclipse.core.runtime.IPath; |
41 |
import org.eclipse.core.runtime.IPath; |
| 42 |
import org.eclipse.core.runtime.IStatus; |
42 |
import org.eclipse.core.runtime.IStatus; |
| 43 |
import org.eclipse.core.runtime.NullProgressMonitor; |
43 |
import org.eclipse.core.runtime.NullProgressMonitor; |
|
|
44 |
import org.eclipse.core.runtime.OperationCanceledException; |
| 44 |
import org.eclipse.core.runtime.Path; |
45 |
import org.eclipse.core.runtime.Path; |
| 45 |
import org.eclipse.core.runtime.Platform; |
46 |
import org.eclipse.core.runtime.Platform; |
| 46 |
import org.eclipse.core.runtime.QualifiedName; |
47 |
import org.eclipse.core.runtime.QualifiedName; |
|
Lines 97-177
Link Here
|
| 97 |
*/ |
98 |
*/ |
| 98 |
public class ModelManagerImpl implements IModelManager { |
99 |
public class ModelManagerImpl implements IModelManager { |
| 99 |
|
100 |
|
| 100 |
private static long WAIT_INTERVAL_MS = 500; |
101 |
|
|
|
102 |
|
| 101 |
static class ReadEditType { |
103 |
static class ReadEditType { |
| 102 |
ReadEditType(String type) { |
104 |
ReadEditType(String type) { |
| 103 |
} |
105 |
} |
| 104 |
} |
106 |
} |
| 105 |
|
107 |
|
| 106 |
/** |
108 |
class SharedObject { |
| 107 |
* A Data class to track our shared objects |
|
|
| 108 |
*/ |
| 109 |
static class SharedObject { |
| 110 |
int referenceCountForEdit; |
109 |
int referenceCountForEdit; |
| 111 |
int referenceCountForRead; |
110 |
int referenceCountForRead; |
| 112 |
IStructuredModel theSharedModel; |
111 |
volatile IStructuredModel theSharedModel; |
|
|
112 |
final ILock LOAD_LOCK = Job.getJobManager().newLock(); |
| 113 |
volatile boolean initializing = true; |
113 |
volatile boolean initializing = true; |
| 114 |
volatile boolean doWait = true; |
114 |
volatile boolean doWait = true; |
| 115 |
|
115 |
// The field 'id' is only meant for debug |
| 116 |
SharedObject(IStructuredModel sharedModel) { |
116 |
volatile String id; |
| 117 |
theSharedModel = sharedModel; |
117 |
|
| 118 |
referenceCountForRead = 0; |
118 |
SharedObject(String id) { |
| 119 |
referenceCountForEdit = 0; |
119 |
this.id=id; |
|
|
120 |
// be aware, this lock will leak and cause the deadlock detector to be horrible if we never release it |
| 121 |
LOAD_LOCK.acquire(); |
| 120 |
} |
122 |
} |
| 121 |
|
123 |
|
| 122 |
/** |
124 |
/** |
| 123 |
* Waits until this shared object has been attempted to be loaded. |
125 |
* Waits until this shared object has been attempted to be loaded. The |
| 124 |
* The load is "attempted" because not all loads result in a model. |
126 |
* load is "attempted" because not all loads result in a model. However, |
| 125 |
* However, upon leaving this method, theShareModel variable |
127 |
* upon leaving this method, theShareModel variable is up-to-date. |
| 126 |
* is up-to-date. |
|
|
| 127 |
*/ |
128 |
*/ |
| 128 |
public void waitForLoadAttempt() { |
129 |
public void waitForLoadAttempt() { |
|
|
130 |
final boolean allowInterrupt = PrefUtil.ALLOW_INTERRUPT_WAITING_THREAD; |
| 131 |
final long timeLimit = (PrefUtil.WAIT_DELAY==0) ? Long.MAX_VALUE : PrefUtil.now() + PrefUtil.WAIT_DELAY; |
| 132 |
final Job current = Job.getJobManager().currentJob(); |
| 129 |
boolean interrupted = false; |
133 |
boolean interrupted = false; |
| 130 |
try { |
134 |
try { |
| 131 |
// if we have a rule, then use a polling system with |
135 |
while (initializing) { |
| 132 |
// short-circuit, otherwise use wait/notify |
136 |
if (current!=null) { |
| 133 |
if (Job.getJobManager().currentRule() != null) { |
137 |
current.yieldRule(null); |
| 134 |
while (initializing) { |
|
|
| 135 |
Job.getJobManager().currentJob().yieldRule(null); |
| 136 |
synchronized (this) { |
| 137 |
if (initializing) { |
| 138 |
try { |
| 139 |
wait(WAIT_INTERVAL_MS); |
| 140 |
} |
| 141 |
catch (InterruptedException e) { |
| 142 |
interrupted = true; |
| 143 |
} |
| 144 |
} |
| 145 |
} |
| 146 |
} |
138 |
} |
| 147 |
} |
139 |
try { |
| 148 |
else { |
140 |
loop(); |
| 149 |
synchronized (this) { |
141 |
} catch (InterruptedException e) { |
| 150 |
while (initializing) { |
142 |
if (allowInterrupt) { |
| 151 |
try { |
143 |
throw new OperationCanceledException("Waiting thread interrupted while waiting for model id: "+id + " to load"); |
| 152 |
wait(); |
144 |
} else { |
| 153 |
} |
145 |
interrupted=true; |
| 154 |
catch (InterruptedException e) { |
|
|
| 155 |
interrupted = true; |
| 156 |
} |
| 157 |
} |
146 |
} |
| 158 |
} |
147 |
} |
|
|
148 |
if (PrefUtil.now() >= timeLimit ) |
| 149 |
throw new OperationCanceledException("Waiting thread timeout exceeded while waiting for model id: "+id + " to load"); |
| 159 |
} |
150 |
} |
| 160 |
} |
151 |
} |
| 161 |
finally { |
152 |
finally { |
| 162 |
if (interrupted) |
153 |
if (interrupted) { |
| 163 |
Thread.currentThread().interrupt(); |
154 |
Thread.currentThread().interrupt(); |
|
|
155 |
} |
| 164 |
} |
156 |
} |
| 165 |
} |
157 |
} |
| 166 |
|
158 |
|
|
|
159 |
private void loop() throws InterruptedException { |
| 160 |
if (initializing) { |
| 161 |
if (LOAD_LOCK.acquire(PrefUtil.WAIT_INTERVAL_MS)) { |
| 162 |
// if we got the lock, but initializing is still not true the deadlock detector gave us |
| 163 |
// the lock and caused reentrancy into this critical section. This is invalid and the |
| 164 |
// sign of a cyclical load attempt. In this case, we through an |
| 165 |
// OperationCanceledException in lew of entering a spin-loop. |
| 166 |
if (initializing) { |
| 167 |
LOAD_LOCK.release(); |
| 168 |
throw new OperationCanceledException("Aborted cyclic load attempt for model with id: "+ id ); |
| 169 |
} else { |
| 170 |
LOAD_LOCK.release(); |
| 171 |
} |
| 172 |
} |
| 173 |
} |
| 174 |
} |
| 175 |
|
| 167 |
/** |
176 |
/** |
| 168 |
* Flags this model as loaded. All waiting methods on |
177 |
* Flags this model as loaded. All waiting methods on |
| 169 |
* {@link #waitForLoadAttempt()} will proceed after this |
178 |
* {@link #waitForLoadAttempt()} will proceed after this method returns. |
| 170 |
* method returns. |
|
|
| 171 |
*/ |
179 |
*/ |
| 172 |
public synchronized void setLoaded() { |
180 |
public void setLoaded() { |
| 173 |
initializing = false; |
181 |
initializing = false; |
| 174 |
notifyAll(); |
182 |
LOAD_LOCK.release(); |
| 175 |
} |
183 |
} |
| 176 |
} |
184 |
} |
| 177 |
|
185 |
|
|
Lines 239-245
Link Here
|
| 239 |
SharedObject testObject = (SharedObject) fManagedObjects.get(id); |
247 |
SharedObject testObject = (SharedObject) fManagedObjects.get(id); |
| 240 |
if (testObject==null) { |
248 |
if (testObject==null) { |
| 241 |
// null means it's been disposed, we need to do the work to reload it. |
249 |
// null means it's been disposed, we need to do the work to reload it. |
| 242 |
sharedObject = new SharedObject(null); |
250 |
sharedObject = new SharedObject(id); |
| 243 |
fManagedObjects.put(id, sharedObject); |
251 |
fManagedObjects.put(id, sharedObject); |
| 244 |
SYNC.release(); |
252 |
SYNC.release(); |
| 245 |
_doCommonCreateModel(file, id, handler, resolver, rwType, encodingRule, |
253 |
_doCommonCreateModel(file, id, handler, resolver, rwType, encodingRule, |
|
Lines 350-356
Link Here
|
| 350 |
SharedObject testObject = (SharedObject) fManagedObjects.get(id); |
358 |
SharedObject testObject = (SharedObject) fManagedObjects.get(id); |
| 351 |
if (testObject==null) { |
359 |
if (testObject==null) { |
| 352 |
// it was removed ,so lets create it |
360 |
// it was removed ,so lets create it |
| 353 |
sharedObject = new SharedObject(null); |
361 |
sharedObject = new SharedObject(id); |
| 354 |
fManagedObjects.put(id, sharedObject); |
362 |
fManagedObjects.put(id, sharedObject); |
| 355 |
SYNC.release(); |
363 |
SYNC.release(); |
| 356 |
_doCommonCreateModel(inputStream, id, handler, resolver, rwType, |
364 |
_doCommonCreateModel(inputStream, id, handler, resolver, rwType, |
|
Lines 491-497
Link Here
|
| 491 |
SharedObject testObject = (SharedObject) fManagedObjects.get(id); |
499 |
SharedObject testObject = (SharedObject) fManagedObjects.get(id); |
| 492 |
if (testObject==null) { |
500 |
if (testObject==null) { |
| 493 |
// it was removed ,so lets create it |
501 |
// it was removed ,so lets create it |
| 494 |
sharedObject = new SharedObject(null); |
502 |
sharedObject = new SharedObject(id); |
| 495 |
fManagedObjects.put(id, sharedObject); |
503 |
fManagedObjects.put(id, sharedObject); |
| 496 |
|
504 |
|
| 497 |
SYNC.release(); |
505 |
SYNC.release(); |
|
Lines 567-573
Link Here
|
| 567 |
throw new ResourceInUse(); |
575 |
throw new ResourceInUse(); |
| 568 |
} |
576 |
} |
| 569 |
|
577 |
|
| 570 |
sharedObject = new SharedObject(null); |
578 |
sharedObject = new SharedObject(id); |
| 571 |
fManagedObjects.put(id, sharedObject); |
579 |
fManagedObjects.put(id, sharedObject); |
| 572 |
|
580 |
|
| 573 |
} finally { |
581 |
} finally { |
|
Lines 612-618
Link Here
|
| 612 |
SYNC.acquire(); |
620 |
SYNC.acquire(); |
| 613 |
SharedObject testObject = (SharedObject) fManagedObjects.get(id); |
621 |
SharedObject testObject = (SharedObject) fManagedObjects.get(id); |
| 614 |
if (testObject==null) { |
622 |
if (testObject==null) { |
| 615 |
sharedObject = new SharedObject(null); |
623 |
sharedObject = new SharedObject(id); |
| 616 |
fManagedObjects.put(id, sharedObject); |
624 |
fManagedObjects.put(id, sharedObject); |
| 617 |
SYNC.release(); |
625 |
SYNC.release(); |
| 618 |
synchronized(sharedObject) { |
626 |
synchronized(sharedObject) { |
|
Lines 830-836
Link Here
|
| 830 |
if (sharedObject != null) { |
838 |
if (sharedObject != null) { |
| 831 |
throw new ResourceInUse(); |
839 |
throw new ResourceInUse(); |
| 832 |
} |
840 |
} |
| 833 |
sharedObject = new SharedObject(null); |
841 |
sharedObject = new SharedObject(newId); |
| 834 |
fManagedObjects.put(newId,sharedObject); |
842 |
fManagedObjects.put(newId,sharedObject); |
| 835 |
} finally { |
843 |
} finally { |
| 836 |
SYNC.release(); |
844 |
SYNC.release(); |