KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > ui > monitors > MonitorManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.debug.ui.monitors;
12
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Hashtable JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import org.eclipse.debug.core.DebugException;
22 import org.eclipse.debug.core.model.IThread;
23 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
24 import org.eclipse.jdt.debug.core.IJavaObject;
25 import org.eclipse.jdt.debug.core.IJavaThread;
26 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
27
28 /**
29  * Handles all the data for the Threads and Monitors view.
30  */

31
32 public class MonitorManager {
33     
34     /**
35      * Table containing the references to the monitors owned by the threads
36      */

37     private Map JavaDoc fThreadToOwnedMonitors;
38
39     /**
40      * Table containing the references to the monitor contended by the threads
41      */

42     private Map JavaDoc fThreadToContendedMonitor;
43
44     /**
45      * Table containing the references to the thread owning the monitors
46      */

47     private Map JavaDoc fMonitorToOwningThread;
48     
49     /**
50      * Table containing the references to the threads contending the monitors
51      */

52     private Map JavaDoc fMonitorToContendingThreads;
53     
54     private static MonitorManager fgDefault= null;
55     
56     private DeadLocksViewContentProvider fDeadlockUpdateListener;
57     
58     /**
59      * List containing the lists of the different deadlocks
60      */

61     private List JavaDoc fDeadLockLists;
62
63     /**
64      * Constructor
65      */

66     private MonitorManager() {
67         //@see getDefault()
68
fThreadToOwnedMonitors= new Hashtable JavaDoc(4);
69         fThreadToContendedMonitor= new Hashtable JavaDoc(4);
70         fMonitorToOwningThread= new Hashtable JavaDoc();
71         fMonitorToContendingThreads= new Hashtable JavaDoc();
72         fDeadLockLists = new ArrayList JavaDoc();
73     }
74
75     public static MonitorManager getDefault() {
76         if (fgDefault == null) {
77             fgDefault= new MonitorManager();
78         }
79         return fgDefault;
80     }
81     
82     /**
83      * Adds the the monitors owned by the thread
84      * If the list is <code>null</code>, remove the thread from the mappings
85      * @param thread The thread
86      * @param monitors The monitors owned by the thread
87      */

88     protected void addThreadWithOwnedMonitors(IJavaThread thread, IJavaObject[] monitors) {
89         if (monitors == null) {
90             fThreadToOwnedMonitors.remove(thread);
91         } else {
92             fThreadToOwnedMonitors.put(thread, monitors);
93         }
94     }
95     
96     /**
97      * Adds the monitor contended by the thread
98      * If the list is <code>null</code>, remove the thread from the mappings
99      * @param thread The thread
100      * @param monitor The monitor contended by the thread
101      */

102     protected void addThreadWithContendedMonitor(IJavaThread thread, IJavaObject monitor) {
103         if (monitor == null) {
104             fThreadToContendedMonitor.remove(thread);
105         } else {
106             fThreadToContendedMonitor.put(thread, monitor);
107         }
108     }
109
110     /**
111      * Adds the thread owning the monitor
112      * If the list is <code>null</code>, remove the monitor from the mappings
113      * @param monitor The monitor
114      * @param thread The thread owning the monitor
115      */

116     protected void addMonitorWithOwningThread(IJavaObject monitor, IJavaThread thread) {
117         if (monitor == null) {
118             fMonitorToOwningThread.remove(monitor);
119         } else {
120             fMonitorToOwningThread.put(monitor, thread);
121         }
122     }
123     
124     /**
125      * Adds a thread waiting for the monitor
126      * If the list is <code>null</code>, remove the monitors from the mappings
127      * @param monitor The monitor
128      * @param thread The thread waiting for the monitor
129      */

130     protected void addMonitorWithContendedThread(IJavaObject monitor, IJavaThread thread) {
131         if (monitor == null) {
132             fMonitorToContendingThreads.remove(monitor);
133         } else {
134             List JavaDoc threads= (List JavaDoc)fMonitorToContendingThreads.get(monitor);
135             if (threads == null) {
136                 threads= new ArrayList JavaDoc();
137                 fMonitorToContendingThreads.put(monitor, threads);
138             }
139             threads.add(thread);
140         }
141     }
142         
143     /**
144      * Returns the monitors owned by the given thread, or <code>null</code>
145      * if the thread does not own any monitors.
146      *
147      * @param thread The thread owning the monitors
148      * @return The monitors owned by the given thread
149      */

150     public IJavaObject[] getOwnedMonitors(IJavaThread thread) {
151         return (IJavaObject[])fThreadToOwnedMonitors.get(thread);
152     }
153
154     /**
155      * Returns the monitor contended by the given thread, or <code>null</code>
156      *
157      * @param thread The thread from to determine the contended monitor
158      * @return The monitor contended by the given thread
159      */

160     public IJavaObject getContendedMonitor(IJavaThread thread) {
161         return (IJavaObject)fThreadToContendedMonitor.get(thread);
162     }
163     
164     /**
165      * Returns the thread owning the given monitor, or <code>null</code>
166      * if no thread owns the specified monitor.
167      *
168      * @param monitor The monitor from to determine the owning thread
169      * @return The thread owning the given monitor
170      */

171     public IJavaThread getOwningThread(IJavaObject monitor) {
172         return (IJavaThread)fMonitorToOwningThread.get(monitor);
173     }
174     
175     /**
176      * Returns the list of threads awaiting the given monitor, or <code>null</code>
177      *
178      * @param monitor The monitor from to determine the contending threads
179      * @return List a list of the threads in contention for the monitor
180      */

181     public List JavaDoc getContendingThreads(IJavaObject monitor) {
182         Object JavaDoc obj = fMonitorToContendingThreads.get(monitor);
183         return (List JavaDoc)obj;
184     }
185     
186     /**
187      * Returns all the threads owning or waiting on a monitor
188      *
189      * @return All the threads (owning or waiting on a monitor)
190      */

191     public IJavaThread[] getThreads() {
192         Set JavaDoc all= new HashSet JavaDoc();
193         all.addAll(fThreadToContendedMonitor.keySet());
194         all.addAll(fThreadToOwnedMonitors.keySet());
195         return (IJavaThread[])all.toArray(new IJavaThread[all.size()]);
196     }
197     
198     /**
199      * Returns all the monitors owned or in contention.
200      *
201      * @return All the monitors (owned or in contention)
202      */

203     public IJavaObject[] getMonitors() {
204         Set JavaDoc all= new HashSet JavaDoc();
205         all.addAll(fMonitorToContendingThreads.keySet());
206         all.addAll(fMonitorToOwningThread.keySet());
207         return (IJavaObject[])all.toArray(new IJavaObject[all.size()]);
208     }
209     
210     /**
211      * Updates the data on threads, monitors and deadlocks
212      * for the specified debug target.
213      *
214      * @param target The debug target
215      */

216     public void update(IJavaDebugTarget target){
217         
218         removeMonitorInformation(target);
219
220         if (!target.supportsMonitorInformation()) {
221             return;
222         }
223         if (fDeadlockUpdateListener != null) {
224             fDeadlockUpdateListener.clearDeadlockInformation();
225         }
226         update(target, true);
227     }
228         
229     /**
230      * Updates the data on threads, monitors and deadlocks
231      * for the suspended threads contained within the specified
232      * debug target.
233      *
234      * @param target The debug target
235      * @see update(IJavaDebugTarget target)
236      */

237     public void updatePartial(IJavaDebugTarget target){
238             
239         removeMonitorInformation(target);
240
241         if (!target.supportsMonitorInformation()) {
242             return;
243         }
244         
245         if (fDeadlockUpdateListener != null) {
246             fDeadlockUpdateListener.clearDeadlockInformation();
247         }
248         
249         update(target, false);
250     }
251     
252     /**
253      * Updates the data on threads, monitors and deadlocks
254      * for the suspended threads contained within the specified
255      * debug target. If <code>suspendThreads</code>, all the non-system
256      * threads are suspended.
257      *
258      * @param target The debug target
259      * @param whether to suspend the threads
260      */

261     private void update(IJavaDebugTarget target, boolean suspendThreads){
262
263         try {
264             // construct the list of all the non system threads
265
IThread[] threadResult= target.getThreads();
266             List JavaDoc threadsList = new ArrayList JavaDoc(threadResult.length);
267             IJavaThread thread;
268             for (int i = 0; i < threadResult.length; i++) {
269                 thread = (IJavaThread)threadResult[i];
270                 threadsList.add(thread);
271             }
272             IJavaThread[] threads= (IJavaThread[]) threadsList.toArray(new IJavaThread[threadsList.size()]);
273             
274             if (suspendThreads) {
275                 //suspend all the non system threads
276
suspend(threads);
277             }
278             
279             //updating data on owning threads / owned monitors
280
// and contending threads / contended monitors
281
for (int i = 0; i < threads.length; i++) {
282                 thread = threads[i];
283                 updateMonitors(thread);
284             }
285             //all of the monitor information is needed before
286
//the deadlock information can be calculated
287
for (int i = 0; i < threads.length; i++) {
288                 thread = threads[i];
289                 updateDeadlock(thread);
290             }
291         } catch(DebugException e){
292         }
293     }
294
295     private void updateDeadlock(IJavaThread thread) {
296         //updating data on deadlocks
297
List JavaDoc l = listToDeadlock(thread, new ArrayList JavaDoc(4));
298         // if thread is caught in a deadlock,
299
// l will be the list showing this deadlock
300
if(l != null){
301             ThreadWrapper tw = new ThreadWrapper(thread, l);
302             // adding this deadlock list
303
fDeadLockLists.add(tw);
304         }
305     }
306     
307     private void updateMonitors(IJavaThread thread) throws DebugException {
308         IJavaObject[] ownedMonitors;
309         IJavaObject currentContendedMonitor;
310         IJavaObject monitor;
311         ownedMonitors = thread.getOwnedMonitors();
312         currentContendedMonitor = thread.getContendedMonitor();
313         // owning threads / owned monitors
314
if(thread.hasOwnedMonitors()){
315             addThreadWithOwnedMonitors(thread, ownedMonitors);
316             
317             for(int j=0; j < ownedMonitors.length; j++) {
318                 monitor = ownedMonitors[j];
319                 addMonitorWithOwningThread(monitor, thread);
320             }
321         }
322         // contending threads / contended monitors
323
if(currentContendedMonitor != null){
324             addThreadWithContendedMonitor(thread, currentContendedMonitor);
325             addMonitorWithContendedThread(currentContendedMonitor, thread);
326         }
327     }
328
329     /**
330      * Suspend all the given threads
331      * @param The list of threads to suspend
332      */

333     private void suspend(IJavaThread[] threads){
334         try {
335             for (int i = 0; i < threads.length; i++) {
336                 IJavaThread thread = threads[i];
337                 if (!thread.isSuspended()) {
338                     thread.suspend();
339                     while (!thread.isSuspended()) {
340                         Thread.sleep(100);
341                     }
342                 }
343             }
344         }
345         catch (DebugException e) {
346             JDIDebugUIPlugin.log(e);
347         }
348         catch (InterruptedException JavaDoc e){
349             JDIDebugUIPlugin.log(e);
350         }
351     }
352     
353     /**
354      * Clears all the cached monitor information for the specified target.
355      *
356      * @param target The target to remove the cached information for
357      */

358     public void removeMonitorInformation(IJavaDebugTarget target) {
359         fThreadToOwnedMonitors.clear();
360         fThreadToContendedMonitor.clear();
361         fMonitorToOwningThread.clear();
362         fMonitorToContendingThreads.clear();
363         fDeadLockLists.clear();
364         if (fDeadlockUpdateListener != null) {
365             fDeadlockUpdateListener.clearDeadlockInformation();
366         }
367     }
368     
369     /**
370      * If the thread is in a deadlock, returns the list to the deadlock
371      * This list has the following structure:
372      * <ul>
373      * <li>First element: Thread in the deadlock or waiting on a monitor that is involved in a deadlock</li>
374      * <li>Second element: Monitor contended by the first element</li>
375      * <li>Third element: Thread owning the second element</li>
376      * <li>Fourth element: Monitor contended by the third element</li>
377      * <li>...</li>
378      * <li>Last element: Same element as the first one, proving that it is in a deadlock</li>
379      * </ul>
380      *
381      * @param thread The thread we want to get the list of
382      * @param threadTree The list that records the element already used (call with an empty list)
383      * @return The deadlock list
384      */

385     private List JavaDoc listToDeadlock(IJavaThread thread, List JavaDoc usedThreadsList){
386         
387         List JavaDoc res = new ArrayList JavaDoc();
388         IJavaObject contendedMonitor = (IJavaObject)fThreadToContendedMonitor.get(thread);
389                         
390         //if the thread is waiting for one monitor
391
if(contendedMonitor!=null){
392             
393             IJavaThread owningThread = (IJavaThread)fMonitorToOwningThread.get(contendedMonitor);
394             // check if owningThread has already been used, and therefore is already in the given list
395
// if owningThread has already been used, returns the end of the list
396
if(usedThreadsList.contains(owningThread)){
397                 res.add(thread);
398                 res.add(contendedMonitor);
399                 res.add(owningThread);
400                 return res;
401             }
402             // if owningThread has not already been used
403
else{
404                 List JavaDoc newUsedThreadsList= new ArrayList JavaDoc(usedThreadsList);
405                 
406                 //adding current thread to the new used list
407
newUsedThreadsList.add(thread);
408                 
409                 if(owningThread==null){
410                     return null;
411                 }
412                 // recursive call, one level lower in the deadlock list
413
List JavaDoc newRes = listToDeadlock(owningThread, newUsedThreadsList);
414                     
415                 if(newRes!=null){
416                     res.add(thread);
417                     res.add(contendedMonitor);
418                     res.addAll(newRes);
419                     return res;
420                 }
421             }
422         } else {
423             // if the thread is not waiting for any monitor
424
return null;
425         }
426         return null;
427     }
428     
429     /**
430      * Returns the number of determined deadlocks
431      *
432      * @return List a list of all of the listings of current deadlocks
433      */

434     public int getNumberOfDeadlocks() {
435         return fDeadLockLists.size();
436     }
437     
438     /**
439      * Returns the deadlock list at the specified index or <code>null</code>
440      * if the index is greater than the number of detected deadlocks.
441      *
442      * @return List a list of all of the listings of current deadlocks
443      * @see getNumberOfDeadlocks();
444      */

445     public List JavaDoc getDeadlockList(int index) {
446         if (index >= fDeadLockLists.size()) {
447             return null;
448         }
449         return ((ThreadWrapper)fDeadLockLists.get(index)).getDeadLockList();
450     }
451     
452     /**
453      * Returns the thread that is at the root of the deadlock at the specified
454      * index or <code>null</code> if the index is greater than the number of
455      * detected deadlocks.
456      *
457      * @return IJavaThread the thread at the root of the deadlock
458      * @see getNumberOfDeadlocks();
459      */

460     public IJavaThread getStartThread(int index) {
461         if (index >= fDeadLockLists.size()) {
462             return null;
463         }
464         return ((ThreadWrapper)fDeadLockLists.get(index)).getStartThread();
465     }
466     
467     /**
468      * Returns whether the given thread is caught in a deadlock
469      *
470      * @param thread The thread to check if in deadlock
471      * @return <code>true<code> if the thread is in a deadlock, <code>false<code> otherwise.
472      */

473     public boolean isCaughtInDeadlock(IJavaThread thread){
474         for (int i = 0; i < fDeadLockLists.size(); i++) {
475             if(((ThreadWrapper)fDeadLockLists.get(i)).getStartThread().equals(thread)){
476                 return true;
477             }
478         }
479         return false;
480     }
481     
482     protected void addDeadlockUpdateListener(DeadLocksViewContentProvider provider) {
483         fDeadlockUpdateListener= provider;
484     }
485     
486     protected void removeDeadlockUpdateListener() {
487         fDeadlockUpdateListener= null;
488     }
489 }
490
Popular Tags