KickJava   Java API By Example, From Geeks To Geeks.

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


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

11 package org.eclipse.jdt.internal.debug.ui.monitors;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Map JavaDoc;
18
19 import org.eclipse.core.runtime.IAdaptable;
20 import org.eclipse.debug.core.DebugEvent;
21 import org.eclipse.debug.core.DebugPlugin;
22 import org.eclipse.debug.core.IDebugEventSetListener;
23 import org.eclipse.debug.core.model.IDebugElement;
24 import org.eclipse.debug.core.model.IThread;
25 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
26 import org.eclipse.jdt.debug.core.IJavaObject;
27 import org.eclipse.jdt.debug.core.IJavaThread;
28 import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
29 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
30 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPreferenceInitializer;
31 import org.eclipse.jface.preference.IPreferenceStore;
32 import org.eclipse.jface.util.IPropertyChangeListener;
33 import org.eclipse.jface.util.PropertyChangeEvent;
34
35 /**
36  * Manager for the thread and monitor model.
37  */

38 public class ThreadMonitorManager implements IDebugEventSetListener, IPropertyChangeListener {
39     
40     private static ThreadMonitorManager fDefaultManager;
41     
42     /**
43      * HashMap IJavaThread -> JavaMonitorThread
44      */

45     private HashMap JavaDoc fJavaMonitorThreads;
46     /**
47      * HashMap IJavaObject -> JavaMonitor
48      */

49     private HashMap JavaDoc fJavaMonitors;
50     
51     private boolean fIsEnabled;
52     
53     /**
54      * Returns the default ThreadMonitorManager object.
55      */

56     public static ThreadMonitorManager getDefault() {
57         if (fDefaultManager == null) {
58             fDefaultManager= new ThreadMonitorManager();
59         }
60         return fDefaultManager;
61     }
62     
63     private ThreadMonitorManager() {
64         fJavaMonitorThreads= new HashMap JavaDoc();
65         fJavaMonitors= new HashMap JavaDoc();
66         IPreferenceStore preferenceStore = JDIDebugUIPlugin.getDefault().getPreferenceStore();
67         preferenceStore.addPropertyChangeListener(this);
68         fIsEnabled= preferenceStore.getBoolean(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO);
69         if (fIsEnabled) {
70             DebugPlugin.getDefault().addDebugEventListener(this);
71         }
72     }
73
74     /* (non-Javadoc)
75      * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[])
76      */

77     public void handleDebugEvents(DebugEvent[] events) {
78         for (int i= 0; i < events.length; i++) {
79             DebugEvent debugEvent= events[i];
80             Object JavaDoc eventSource= debugEvent.getSource();
81             int eventKind= debugEvent.getKind();
82             IJavaThread javaThread = null;
83             if (eventSource instanceof IAdaptable) {
84                 IAdaptable adaptable = (IAdaptable)eventSource;
85                 javaThread = (IJavaThread) adaptable.getAdapter(IJavaThread.class);
86                 if (javaThread != null) {
87                     switch (eventKind) {
88                         case DebugEvent.SUSPEND:
89                         case DebugEvent.RESUME:
90                             // refresh on suspend/resume
91
if (debugEvent.getDetail() != DebugEvent.EVALUATION_IMPLICIT) {
92                                 handleSuspendResume();
93                             }
94                             break;
95                         case DebugEvent.TERMINATE:
96                             // clean the thread map when a thread terminates
97
handleThreadTerminate(javaThread);
98                             break;
99                     }
100                 } else {
101                     IJavaDebugTarget target = (IJavaDebugTarget) adaptable.getAdapter(IJavaDebugTarget.class);
102                     if (target != null) {
103                         switch (eventKind) {
104                             case DebugEvent.SUSPEND:
105                             case DebugEvent.RESUME:
106                                 // refresh on suspend/resume
107
if (debugEvent.getDetail() != DebugEvent.EVALUATION_IMPLICIT) {
108                                     handleSuspendResume();
109                                 }
110                                 break;
111                             case DebugEvent.TERMINATE:
112                                 // clean the maps when a target terminates
113
handleDebugTargetTerminate(target);
114                                 break;
115                         }
116                     }
117                 }
118             }
119         }
120     }
121     
122     private void handleSuspendResume() {
123         JavaMonitorThread[] threads = getJavaMonitorThreads();
124         for (int i = 0; i < threads.length; i++) {
125             threads[i].setToUpdate();
126         }
127         DebugPlugin.getDefault().asyncExec(new RefreshAndDetectDeadlock());
128     }
129
130     private void handleThreadTerminate(IJavaThread thread) {
131         // remove this thread
132
synchronized(fJavaMonitorThreads) {
133             fJavaMonitorThreads.remove(thread);
134         }
135     }
136
137     private void handleDebugTargetTerminate(IJavaDebugTarget debugTarget) {
138         // remove the threads and monitors for this debug target.
139
clean(fJavaMonitors, debugTarget);
140         clean(fJavaMonitorThreads, debugTarget);
141     }
142
143     private void clean(Map JavaDoc map, IJavaDebugTarget debugTarget) {
144         IDebugElement debugElements[] = null;
145         synchronized(map) {
146             debugElements = new IDebugElement[map.size()];
147             debugElements = (IDebugElement[]) map.keySet().toArray(debugElements);
148         }
149         for(int i = 0; i < debugElements.length; ++i) {
150             if (debugElements[i].getDebugTarget().equals(debugTarget)) {
151                 synchronized(map) {
152                     map.remove(debugElements[i]);
153                 }
154             }
155         }
156     }
157     
158     /**
159      * Returns the unique JavaMonitorThread object for the given thread.
160      */

161     protected JavaMonitorThread getJavaMonitorThread(IJavaThread thread, IThread originalThread) {
162         synchronized (fJavaMonitorThreads) {
163             JavaMonitorThread javaMonitorThread= (JavaMonitorThread) fJavaMonitorThreads.get(thread);
164             if (javaMonitorThread == null) {
165                 javaMonitorThread= new JavaMonitorThread(thread, originalThread);
166                 fJavaMonitorThreads.put(thread, javaMonitorThread);
167                 DebugPlugin.getDefault().asyncExec(new DetectDeadlock());
168             } else if (originalThread != null) {
169                 javaMonitorThread.setOriginalThread(originalThread);
170             }
171             return javaMonitorThread;
172         }
173     }
174     
175     /**
176      * Returns the unique JavaMonitor object for the given monitor.
177      */

178     protected JavaMonitor getJavaMonitor(IJavaObject monitor) {
179         synchronized (fJavaMonitors) {
180             JavaMonitor javaMonitor= (JavaMonitor) fJavaMonitors.get(monitor);
181             if (javaMonitor == null) {
182                 javaMonitor= new JavaMonitor(monitor);
183                 fJavaMonitors.put(monitor, javaMonitor);
184             }
185             return javaMonitor;
186         }
187     }
188
189     /**
190      * Removes a monitor from the monitor map.
191      */

192     protected void removeJavaMonitor(JavaMonitor monitor) {
193         synchronized(fJavaMonitors) {
194             fJavaMonitors.remove(monitor.getMonitor());
195         }
196     }
197             
198     /**
199      * Returns the monitor the given thread is waiting for.
200      */

201     public JavaContendedMonitor getContendedMonitor(IThread thread) {
202         IJavaThread javaThread = (IJavaThread) thread.getAdapter(IJavaThread.class);
203         if (javaThread == null || !fIsEnabled || !((IJavaDebugTarget)javaThread.getDebugTarget()).supportsMonitorInformation()) {
204             return null;
205         }
206         return getJavaMonitorThread(javaThread, thread).getContendedMonitor();
207     }
208     
209     /**
210      * Returns the monitors the given thread owns.
211      */

212     public JavaOwnedMonitor[] getOwnedMonitors(IThread thread) {
213         IJavaThread javaThread = (IJavaThread) thread.getAdapter(IJavaThread.class);
214         if (javaThread == null || !fIsEnabled || !((IJavaDebugTarget)javaThread.getDebugTarget()).supportsMonitorInformation()) {
215             return new JavaOwnedMonitor[0];
216         }
217         return getJavaMonitorThread(javaThread, thread).getOwnedMonitors();
218     }
219
220     /**
221      * Runnable to be run asynchronously, to refresh the model and
222      * look for deadlocks.
223      */

224     class RefreshAndDetectDeadlock extends DetectDeadlock {
225         public void run() {
226             JavaMonitorThread[] threads= getJavaMonitorThreads();
227             for (int i = 0; i < threads.length; i++) {
228                 threads[i].refresh();
229             }
230             super.run();
231         }
232     }
233
234     class DetectDeadlock implements Runnable JavaDoc {
235         public void run() {
236             JavaMonitorThread[] threads= getJavaMonitorThreads();
237             JavaMonitor[] monitors= getJavaMonitors();
238             List JavaDoc inDeadlock= new ArrayList JavaDoc();
239             for (int i = 0; i < threads.length; i++) {
240                 JavaMonitorThread thread= threads[i];
241                 List JavaDoc threadStack= new ArrayList JavaDoc();
242                 List JavaDoc monitorStack= new ArrayList JavaDoc();
243                 while (thread != null) {
244                     boolean isInDeadlock= false;
245                     if (inDeadlock.contains(thread) || threadStack.contains(thread)) {
246                         isInDeadlock= true;
247                     } else {
248                         JavaMonitor monitor = thread.getContendedMonitor0();
249                         if (monitor == null) {
250                             thread= null;
251                         } else if (inDeadlock.contains(monitor)) {
252                             isInDeadlock= true;
253                         } else {
254                             threadStack.add(thread);
255                             monitorStack.add(monitor);
256                             thread= monitor.getOwningThread0();
257                         }
258                     }
259                     if (isInDeadlock) {
260                         // is in a deadlock, set the elements of the back trace as 'in a deadlock'
261
for (Iterator JavaDoc iter = threadStack.iterator(); iter.hasNext();) {
262                             inDeadlock.add(iter.next());
263                         }
264                         for (Iterator JavaDoc iter = monitorStack.iterator(); iter.hasNext();) {
265                             inDeadlock.add(iter.next());
266                         }
267                         thread= null;
268                     }
269                 }
270             }
271             for (int i = 0; i < threads.length; i++) {
272                 JavaMonitorThread thread= threads[i];
273                 thread.setInDeadlock(inDeadlock.contains(thread));
274             }
275             for (int i = 0; i < monitors.length; i++) {
276                 JavaMonitor monitor= monitors[i];
277                 monitor.setInDeadlock(inDeadlock.contains(monitor));
278             }
279         }
280     }
281
282     /* (non-Javadoc)
283      * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
284      */

285     public void propertyChange(PropertyChangeEvent event) {
286         if (event.getProperty().equals(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO)) {
287             fIsEnabled= JDIDebugUIPreferenceInitializer.getBoolean(event);
288             if (fIsEnabled) {
289                 DebugPlugin.getDefault().addDebugEventListener(this);
290             } else {
291                 DebugPlugin.getDefault().removeDebugEventListener(this);
292             }
293         }
294     }
295     
296     /**
297      * Returns <code>true</code> if SHOW_MONITOR_THREAD_INFO is on and the given thread is
298      * in a deadlock, <code>false</code> otherwise.
299      */

300     public boolean isInDeadlock(IThread thread) {
301         IJavaThread javaThread = (IJavaThread) thread.getAdapter(IJavaThread.class);
302         if (!fIsEnabled || !((IJavaDebugTarget)javaThread.getDebugTarget()).supportsMonitorInformation()) {
303             return false;
304         }
305         return getJavaMonitorThread(javaThread, thread).isInDeadlock();
306     }
307
308     private JavaMonitor[] getJavaMonitors() {
309         synchronized(fJavaMonitors) {
310             JavaMonitor[] monitors = new JavaMonitor[fJavaMonitors.size()];
311             return (JavaMonitor[]) fJavaMonitors.values().toArray(monitors);
312         }
313     }
314     
315     private JavaMonitorThread[] getJavaMonitorThreads() {
316         synchronized(fJavaMonitorThreads) {
317             JavaMonitorThread[] threads = new JavaMonitorThread[fJavaMonitorThreads.size()];
318             return (JavaMonitorThread[]) fJavaMonitorThreads.values().toArray(threads);
319         }
320     }
321 }
322
Popular Tags