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(",");