Mercurial > projects > dwt2
comparison org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/DeadlockDetector.d @ 19:52184e4b815c
no more direct tango.core.Thread. Rename JThread to java.lang.Thread.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Wed, 18 Mar 2009 10:55:25 +0100 |
parents | 735224fcc45f |
children |
comparison
equal
deleted
inserted
replaced
18:735224fcc45f | 19:52184e4b815c |
---|---|
10 * Port to the D programming language: | 10 * Port to the D programming language: |
11 * Frank Benoit <benoit@tionex.de> | 11 * Frank Benoit <benoit@tionex.de> |
12 *******************************************************************************/ | 12 *******************************************************************************/ |
13 module org.eclipse.core.internal.jobs.DeadlockDetector; | 13 module org.eclipse.core.internal.jobs.DeadlockDetector; |
14 | 14 |
15 import java.lang.JThread; | 15 import java.lang.Thread; |
16 | 16 |
17 import java.lang.all; | 17 import java.lang.all; |
18 import java.util.ArrayList; | 18 import java.util.ArrayList; |
19 import java.util.Set; | 19 import java.util.Set; |
20 | 20 |
98 /** | 98 /** |
99 * Recursively check if any of the threads that prevent the current thread from running | 99 * Recursively check if any of the threads that prevent the current thread from running |
100 * are actually deadlocked with the current thread. | 100 * are actually deadlocked with the current thread. |
101 * Add the threads that form deadlock to the deadlockedThreads list. | 101 * Add the threads that form deadlock to the deadlockedThreads list. |
102 */ | 102 */ |
103 private bool addCycleThreads(ArrayList deadlockedThreads, JThread next) { | 103 private bool addCycleThreads(ArrayList deadlockedThreads, Thread next) { |
104 //get the thread that block the given thread from running | 104 //get the thread that block the given thread from running |
105 JThread[] blocking = blockingThreads(next); | 105 Thread[] blocking = blockingThreads(next); |
106 //if the thread is not blocked by other threads, then it is not part of a deadlock | 106 //if the thread is not blocked by other threads, then it is not part of a deadlock |
107 if (blocking.length is 0) | 107 if (blocking.length is 0) |
108 return false; | 108 return false; |
109 bool inCycle = false; | 109 bool inCycle = false; |
110 for (int i = 0; i < blocking.length; i++) { | 110 for (int i = 0; i < blocking.length; i++) { |
125 } | 125 } |
126 | 126 |
127 /** | 127 /** |
128 * Get the thread(s) that own the lock this thread is waiting for. | 128 * Get the thread(s) that own the lock this thread is waiting for. |
129 */ | 129 */ |
130 private JThread[] blockingThreads(JThread current) { | 130 private Thread[] blockingThreads(Thread current) { |
131 //find the lock this thread is waiting for | 131 //find the lock this thread is waiting for |
132 ISchedulingRule lock = cast(ISchedulingRule) getWaitingLock(current); | 132 ISchedulingRule lock = cast(ISchedulingRule) getWaitingLock(current); |
133 return getThreadsOwningLock(lock); | 133 return getThreadsOwningLock(lock); |
134 } | 134 } |
135 | 135 |
164 | 164 |
165 /** | 165 /** |
166 * Returns true IFF the matrix contains a row for the given thread. | 166 * Returns true IFF the matrix contains a row for the given thread. |
167 * (meaning the given thread either owns locks or is waiting for locks) | 167 * (meaning the given thread either owns locks or is waiting for locks) |
168 */ | 168 */ |
169 bool contains(JThread t) { | 169 bool contains(Thread t) { |
170 return lockThreads.contains(t); | 170 return lockThreads.contains(t); |
171 } | 171 } |
172 | 172 |
173 /** | 173 /** |
174 * A new rule was just added to the graph. | 174 * A new rule was just added to the graph. |
197 } | 197 } |
198 | 198 |
199 /** | 199 /** |
200 * Returns all the locks owned by the given thread | 200 * Returns all the locks owned by the given thread |
201 */ | 201 */ |
202 private Object[] getOwnedLocks(JThread current) { | 202 private Object[] getOwnedLocks(Thread current) { |
203 ArrayList ownedLocks = new ArrayList(1); | 203 ArrayList ownedLocks = new ArrayList(1); |
204 int index = indexOf(current, false); | 204 int index = indexOf(current, false); |
205 | 205 |
206 for (int j = 0; j < graph[index].length; j++) { | 206 for (int j = 0; j < graph[index].length; j++) { |
207 if (graph[index][j] > NO_STATE) | 207 if (graph[index][j] > NO_STATE) |
213 } | 213 } |
214 | 214 |
215 /** | 215 /** |
216 * Returns an array of threads that form the deadlock (usually 2). | 216 * Returns an array of threads that form the deadlock (usually 2). |
217 */ | 217 */ |
218 private JThread[] getThreadsInDeadlock(JThread cause) { | 218 private Thread[] getThreadsInDeadlock(Thread cause) { |
219 ArrayList deadlockedThreads = new ArrayList(2); | 219 ArrayList deadlockedThreads = new ArrayList(2); |
220 /** | 220 /** |
221 * if the thread that caused deadlock doesn't own any locks, then it is not part | 221 * if the thread that caused deadlock doesn't own any locks, then it is not part |
222 * of the deadlock (it just caused it because of a rule it tried to acquire) | 222 * of the deadlock (it just caused it because of a rule it tried to acquire) |
223 */ | 223 */ |
224 if (ownsLocks(cause)) | 224 if (ownsLocks(cause)) |
225 deadlockedThreads.add(cause); | 225 deadlockedThreads.add(cause); |
226 addCycleThreads(deadlockedThreads, cause); | 226 addCycleThreads(deadlockedThreads, cause); |
227 return arraycast!(JThread)( deadlockedThreads.toArray()); | 227 return arraycast!(Thread)( deadlockedThreads.toArray()); |
228 } | 228 } |
229 | 229 |
230 /** | 230 /** |
231 * Returns the thread(s) that own the given lock. | 231 * Returns the thread(s) that own the given lock. |
232 */ | 232 */ |
233 private JThread[] getThreadsOwningLock(ISchedulingRule rule) { | 233 private Thread[] getThreadsOwningLock(ISchedulingRule rule) { |
234 if (rule is null) | 234 if (rule is null) |
235 return new JThread[0]; | 235 return new Thread[0]; |
236 int lockIndex = indexOf(rule, false); | 236 int lockIndex = indexOf(rule, false); |
237 ArrayList blocking = new ArrayList(1); | 237 ArrayList blocking = new ArrayList(1); |
238 for (int i = 0; i < graph.length; i++) { | 238 for (int i = 0; i < graph.length; i++) { |
239 if (graph[i][lockIndex] > NO_STATE) | 239 if (graph[i][lockIndex] > NO_STATE) |
240 blocking.add(lockThreads.get(i)); | 240 blocking.add(lockThreads.get(i)); |
241 } | 241 } |
242 if ((blocking.size() is 0) && (JobManager.DEBUG_LOCKS)) | 242 if ((blocking.size() is 0) && (JobManager.DEBUG_LOCKS)) |
243 getDwtLogger.info( __FILE__, __LINE__, "Lock {} is involved in deadlock but is not owned by any thread.", rule ); //$NON-NLS-1$ //$NON-NLS-2$ | 243 getDwtLogger.info( __FILE__, __LINE__, "Lock {} is involved in deadlock but is not owned by any thread.", rule ); //$NON-NLS-1$ //$NON-NLS-2$ |
244 if ((blocking.size() > 1) && (cast(ILock)rule ) && (JobManager.DEBUG_LOCKS)) | 244 if ((blocking.size() > 1) && (cast(ILock)rule ) && (JobManager.DEBUG_LOCKS)) |
245 getDwtLogger.info( __FILE__, __LINE__, "Lock {} is owned by more than 1 thread, but it is not a rule.", rule ); //$NON-NLS-1$ //$NON-NLS-2$ | 245 getDwtLogger.info( __FILE__, __LINE__, "Lock {} is owned by more than 1 thread, but it is not a rule.", rule ); //$NON-NLS-1$ //$NON-NLS-2$ |
246 return arraycast!(JThread)( blocking.toArray()); | 246 return arraycast!(Thread)( blocking.toArray()); |
247 } | 247 } |
248 | 248 |
249 /** | 249 /** |
250 * Returns the lock the given thread is waiting for. | 250 * Returns the lock the given thread is waiting for. |
251 */ | 251 */ |
252 private Object getWaitingLock(JThread current) { | 252 private Object getWaitingLock(Thread current) { |
253 int index = indexOf(current, false); | 253 int index = indexOf(current, false); |
254 //find the lock that this thread is waiting for | 254 //find the lock that this thread is waiting for |
255 for (int j = 0; j < graph[index].length; j++) { | 255 for (int j = 0; j < graph[index].length; j++) { |
256 if (graph[index][j] is WAITING_FOR_LOCK) | 256 if (graph[index][j] is WAITING_FOR_LOCK) |
257 return locks.get(j); | 257 return locks.get(j); |
276 | 276 |
277 /** | 277 /** |
278 * Returns the index of the given thread in the thread array. If the thread | 278 * Returns the index of the given thread in the thread array. If the thread |
279 * is not present in the array, it is added to the end. | 279 * is not present in the array, it is added to the end. |
280 */ | 280 */ |
281 private int indexOf(JThread owner, bool add) { | 281 private int indexOf(Thread owner, bool add) { |
282 int index = lockThreads.indexOf(owner); | 282 int index = lockThreads.indexOf(owner); |
283 if ((index < 0) && add) { | 283 if ((index < 0) && add) { |
284 lockThreads.add(owner); | 284 lockThreads.add(owner); |
285 resize = true; | 285 resize = true; |
286 index = lockThreads.size() - 1; | 286 index = lockThreads.size() - 1; |
296 } | 296 } |
297 | 297 |
298 /** | 298 /** |
299 * The given lock was acquired by the given thread. | 299 * The given lock was acquired by the given thread. |
300 */ | 300 */ |
301 void lockAcquired(JThread owner, ISchedulingRule lock) { | 301 void lockAcquired(Thread owner, ISchedulingRule lock) { |
302 int lockIndex = indexOf(lock, true); | 302 int lockIndex = indexOf(lock, true); |
303 int threadIndex = indexOf(owner, true); | 303 int threadIndex = indexOf(owner, true); |
304 if (resize) | 304 if (resize) |
305 resizeGraph(); | 305 resizeGraph(); |
306 if (graph[threadIndex][lockIndex] is WAITING_FOR_LOCK) | 306 if (graph[threadIndex][lockIndex] is WAITING_FOR_LOCK) |
330 } | 330 } |
331 | 331 |
332 /** | 332 /** |
333 * The given lock was released by the given thread. Update the graph. | 333 * The given lock was released by the given thread. Update the graph. |
334 */ | 334 */ |
335 void lockReleased(JThread owner, ISchedulingRule lock) { | 335 void lockReleased(Thread owner, ISchedulingRule lock) { |
336 int lockIndex = indexOf(lock, false); | 336 int lockIndex = indexOf(lock, false); |
337 int threadIndex = indexOf(owner, false); | 337 int threadIndex = indexOf(owner, false); |
338 //make sure the lock and thread exist in the graph | 338 //make sure the lock and thread exist in the graph |
339 if (threadIndex < 0) { | 339 if (threadIndex < 0) { |
340 if (JobManager.DEBUG_LOCKS) | 340 if (JobManager.DEBUG_LOCKS) |
370 | 370 |
371 /** | 371 /** |
372 * The given scheduling rule is no longer used because the job that invoked it is done. | 372 * The given scheduling rule is no longer used because the job that invoked it is done. |
373 * Release this rule regardless of how many times it was acquired. | 373 * Release this rule regardless of how many times it was acquired. |
374 */ | 374 */ |
375 void lockReleasedCompletely(JThread owner, ISchedulingRule rule) { | 375 void lockReleasedCompletely(Thread owner, ISchedulingRule rule) { |
376 int ruleIndex = indexOf(rule, false); | 376 int ruleIndex = indexOf(rule, false); |
377 int threadIndex = indexOf(owner, false); | 377 int threadIndex = indexOf(owner, false); |
378 //need to make sure that the given thread and rule were not already removed from the graph | 378 //need to make sure that the given thread and rule were not already removed from the graph |
379 if (threadIndex < 0) { | 379 if (threadIndex < 0) { |
380 if (JobManager.DEBUG_LOCKS) | 380 if (JobManager.DEBUG_LOCKS) |
400 | 400 |
401 /** | 401 /** |
402 * The given thread could not get the given lock and is waiting for it. | 402 * The given thread could not get the given lock and is waiting for it. |
403 * Update the graph. | 403 * Update the graph. |
404 */ | 404 */ |
405 Deadlock lockWaitStart(JThread client, ISchedulingRule lock) { | 405 Deadlock lockWaitStart(Thread client, ISchedulingRule lock) { |
406 setToWait(client, lock, false); | 406 setToWait(client, lock, false); |
407 int lockIndex = indexOf(lock, false); | 407 int lockIndex = indexOf(lock, false); |
408 int[] temp = new int[lockThreads.size()]; | 408 int[] temp = new int[lockThreads.size()]; |
409 //check if the addition of the waiting thread caused deadlock | 409 //check if the addition of the waiting thread caused deadlock |
410 if (!checkWaitCycles(temp, lockIndex)) | 410 if (!checkWaitCycles(temp, lockIndex)) |
411 return null; | 411 return null; |
412 //there is a deadlock in the graph | 412 //there is a deadlock in the graph |
413 JThread[] threads = getThreadsInDeadlock(client); | 413 Thread[] threads = getThreadsInDeadlock(client); |
414 JThread candidate = resolutionCandidate(threads); | 414 Thread candidate = resolutionCandidate(threads); |
415 ISchedulingRule[] locksToSuspend = realLocksForThread(candidate); | 415 ISchedulingRule[] locksToSuspend = realLocksForThread(candidate); |
416 Deadlock deadlock = new Deadlock(threads, locksToSuspend, candidate); | 416 Deadlock deadlock = new Deadlock(threads, locksToSuspend, candidate); |
417 //find a thread whose locks can be suspended to resolve the deadlock | 417 //find a thread whose locks can be suspended to resolve the deadlock |
418 if (JobManager.DEBUG_LOCKS) | 418 if (JobManager.DEBUG_LOCKS) |
419 reportDeadlock(deadlock); | 419 reportDeadlock(deadlock); |
429 | 429 |
430 /** | 430 /** |
431 * The given thread has stopped waiting for the given lock. | 431 * The given thread has stopped waiting for the given lock. |
432 * Update the graph. | 432 * Update the graph. |
433 */ | 433 */ |
434 void lockWaitStop(JThread owner, ISchedulingRule lock) { | 434 void lockWaitStop(Thread owner, ISchedulingRule lock) { |
435 int lockIndex = indexOf(lock, false); | 435 int lockIndex = indexOf(lock, false); |
436 int threadIndex = indexOf(owner, false); | 436 int threadIndex = indexOf(owner, false); |
437 //make sure the thread and lock exist in the graph | 437 //make sure the thread and lock exist in the graph |
438 if (threadIndex < 0) { | 438 if (threadIndex < 0) { |
439 if (JobManager.DEBUG_LOCKS) | 439 if (JobManager.DEBUG_LOCKS) |
452 } | 452 } |
453 | 453 |
454 /** | 454 /** |
455 * Returns true IFF the given thread owns a single lock | 455 * Returns true IFF the given thread owns a single lock |
456 */ | 456 */ |
457 private bool ownsLocks(JThread cause) { | 457 private bool ownsLocks(Thread cause) { |
458 int threadIndex = indexOf(cause, false); | 458 int threadIndex = indexOf(cause, false); |
459 for (int j = 0; j < graph[threadIndex].length; j++) { | 459 for (int j = 0; j < graph[threadIndex].length; j++) { |
460 if (graph[threadIndex][j] > NO_STATE) | 460 if (graph[threadIndex][j] > NO_STATE) |
461 return true; | 461 return true; |
462 } | 462 } |
465 | 465 |
466 /** | 466 /** |
467 * Returns true IFF the given thread owns a single real lock. | 467 * Returns true IFF the given thread owns a single real lock. |
468 * A real lock is a lock that can be suspended. | 468 * A real lock is a lock that can be suspended. |
469 */ | 469 */ |
470 private bool ownsRealLocks(JThread owner) { | 470 private bool ownsRealLocks(Thread owner) { |
471 int threadIndex = indexOf(owner, false); | 471 int threadIndex = indexOf(owner, false); |
472 for (int j = 0; j < graph[threadIndex].length; j++) { | 472 for (int j = 0; j < graph[threadIndex].length; j++) { |
473 if (graph[threadIndex][j] > NO_STATE) { | 473 if (graph[threadIndex][j] > NO_STATE) { |
474 Object lock = locks.get(j); | 474 Object lock = locks.get(j); |
475 if (cast(ILock)lock ) | 475 if (cast(ILock)lock ) |
481 | 481 |
482 /** | 482 /** |
483 * Return true IFF this thread owns rule locks (i.e. implicit locks which | 483 * Return true IFF this thread owns rule locks (i.e. implicit locks which |
484 * cannot be suspended) | 484 * cannot be suspended) |
485 */ | 485 */ |
486 private bool ownsRuleLocks(JThread owner) { | 486 private bool ownsRuleLocks(Thread owner) { |
487 int threadIndex = indexOf(owner, false); | 487 int threadIndex = indexOf(owner, false); |
488 for (int j = 0; j < graph[threadIndex].length; j++) { | 488 for (int j = 0; j < graph[threadIndex].length; j++) { |
489 if (graph[threadIndex][j] > NO_STATE) { | 489 if (graph[threadIndex][j] > NO_STATE) { |
490 Object lock = locks.get(j); | 490 Object lock = locks.get(j); |
491 if (!(cast(ILock)lock )) | 491 if (!(cast(ILock)lock )) |
497 | 497 |
498 /** | 498 /** |
499 * Returns an array of real locks that are owned by the given thread. | 499 * Returns an array of real locks that are owned by the given thread. |
500 * Real locks are locks that implement the ILock interface and can be suspended. | 500 * Real locks are locks that implement the ILock interface and can be suspended. |
501 */ | 501 */ |
502 private ISchedulingRule[] realLocksForThread(JThread owner) { | 502 private ISchedulingRule[] realLocksForThread(Thread owner) { |
503 int threadIndex = indexOf(owner, false); | 503 int threadIndex = indexOf(owner, false); |
504 ArrayList ownedLocks = new ArrayList(1); | 504 ArrayList ownedLocks = new ArrayList(1); |
505 for (int j = 0; j < graph[threadIndex].length; j++) { | 505 for (int j = 0; j < graph[threadIndex].length; j++) { |
506 if ((graph[threadIndex][j] > NO_STATE) && (cast(ILock)locks.get(j) )) | 506 if ((graph[threadIndex][j] > NO_STATE) && (cast(ILock)locks.get(j) )) |
507 ownedLocks.add(locks.get(j)); | 507 ownedLocks.add(locks.get(j)); |
606 * Adds a 'deadlock detected' message to the log with a stack trace. | 606 * Adds a 'deadlock detected' message to the log with a stack trace. |
607 */ | 607 */ |
608 private void reportDeadlock(Deadlock deadlock) { | 608 private void reportDeadlock(Deadlock deadlock) { |
609 String msg = "Deadlock detected. All locks owned by thread " ~ deadlock.getCandidate().getName() ~ " will be suspended."; //$NON-NLS-1$ //$NON-NLS-2$ | 609 String msg = "Deadlock detected. All locks owned by thread " ~ deadlock.getCandidate().getName() ~ " will be suspended."; //$NON-NLS-1$ //$NON-NLS-2$ |
610 MultiStatus main = new MultiStatus(JobManager.PI_JOBS, JobManager.PLUGIN_ERROR, msg, new IllegalStateException()); | 610 MultiStatus main = new MultiStatus(JobManager.PI_JOBS, JobManager.PLUGIN_ERROR, msg, new IllegalStateException()); |
611 JThread[] threads = deadlock.getThreads(); | 611 Thread[] threads = deadlock.getThreads(); |
612 for (int i = 0; i < threads.length; i++) { | 612 for (int i = 0; i < threads.length; i++) { |
613 Object[] ownedLocks = getOwnedLocks(threads[i]); | 613 Object[] ownedLocks = getOwnedLocks(threads[i]); |
614 Object waitLock = getWaitingLock(threads[i]); | 614 Object waitLock = getWaitingLock(threads[i]); |
615 StringBuffer buf = new StringBuffer("Thread "); //$NON-NLS-1$ | 615 StringBuffer buf = new StringBuffer("Thread "); //$NON-NLS-1$ |
616 buf.append(threads[i].getName()); | 616 buf.append(threads[i].getName()); |
651 | 651 |
652 /** | 652 /** |
653 * Get the thread whose locks can be suspended. (i.e. all locks it owns are | 653 * Get the thread whose locks can be suspended. (i.e. all locks it owns are |
654 * actual locks and not rules). Return the first thread in the array by default. | 654 * actual locks and not rules). Return the first thread in the array by default. |
655 */ | 655 */ |
656 private JThread resolutionCandidate(JThread[] candidates) { | 656 private Thread resolutionCandidate(Thread[] candidates) { |
657 //first look for a candidate that has no scheduling rules | 657 //first look for a candidate that has no scheduling rules |
658 for (int i = 0; i < candidates.length; i++) { | 658 for (int i = 0; i < candidates.length; i++) { |
659 if (!ownsRuleLocks(candidates[i])) | 659 if (!ownsRuleLocks(candidates[i])) |
660 return candidates[i]; | 660 return candidates[i]; |
661 } | 661 } |
669 } | 669 } |
670 | 670 |
671 /** | 671 /** |
672 * The given thread is waiting for the given lock. Update the graph. | 672 * The given thread is waiting for the given lock. Update the graph. |
673 */ | 673 */ |
674 private void setToWait(JThread owner, ISchedulingRule lock, bool suspend) { | 674 private void setToWait(Thread owner, ISchedulingRule lock, bool suspend) { |
675 bool needTransfer = false; | 675 bool needTransfer = false; |
676 /** | 676 /** |
677 * if we are adding an entry where a thread is waiting on a scheduling rule, | 677 * if we are adding an entry where a thread is waiting on a scheduling rule, |
678 * then we need to transfer all positive entries for a conflicting rule to the | 678 * then we need to transfer all positive entries for a conflicting rule to the |
679 * newly added rule in order to synchronize the graph. | 679 * newly added rule in order to synchronize the graph. |
703 sb.append(","); | 703 sb.append(","); |
704 } | 704 } |
705 sb.append("\n"); | 705 sb.append("\n"); |
706 for (int i = 0; i < graph.length; i++) { | 706 for (int i = 0; i < graph.length; i++) { |
707 sb.append(" "); | 707 sb.append(" "); |
708 sb.append( (cast(JThread) lockThreads.get(i)).getName() ); | 708 sb.append( (cast(Thread) lockThreads.get(i)).getName() ); |
709 sb.append(" : "); | 709 sb.append(" : "); |
710 for (int j = 0; j < graph[i].length; j++) { | 710 for (int j = 0; j < graph[i].length; j++) { |
711 sb.append(" "); | 711 sb.append(" "); |
712 sb.append(Integer.toString(graph[i][j])); //$NON-NLS-1$ | 712 sb.append(Integer.toString(graph[i][j])); //$NON-NLS-1$ |
713 sb.append(","); | 713 sb.append(","); |