/******************************************************************************* * Copyright (c) 2010 Freescale Semiconductor. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Serge Beauchamp (Freescale Semiconductor) - initial API and implementation *******************************************************************************/ package com.freescale.deadlockpreventer.agent; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.regex.Pattern; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.ui.IMemento; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.XMLMemento; import com.freescale.deadlockpreventer.ILock; import com.freescale.deadlockpreventer.NetworkServer.IService; import com.freescale.deadlockpreventer.QueryService; import com.freescale.deadlockpreventer.QueryService.ITransaction; import com.freescale.deadlockpreventer.ReportService; import com.freescale.deadlockpreventer.agent.IAgent.IProcess; import com.freescale.deadlockpreventer.agent.StatisticsDialog.Row; public class InstrumentedProcess implements ReportService.IListener, IProcess { private final class DownloadRunnable implements IRunnableWithProgress { private final ITransaction[] transactions; private final ArrayList<Row> locks; private DownloadRunnable(ITransaction[] transactions, ArrayList<Row> locks) { this.transactions = transactions; this.locks = locks; } @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { transactions[0] = queryService.createTransaction(); int count = transactions[0].getLockCount(); monitor.beginTask("Downloading statistics...", count); int index = 0; int interval = 100; while (index < count) { ILock[] tmp = transactions[0].getLocks(index, Math.min(index + interval, count)); monitor.worked(tmp.length); locks.addAll(Arrays.asList(StatisticsDialog.convert(index, tmp))); index += interval; if (monitor.isCanceled()) break; } monitor.done(); } } private String label; private String reportKey; public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public String getReportKey() { return reportKey; } public String getQueryKey() { return queryKey; } public void setConflictList(ArrayList<Conflict> conflictList) { this.conflictList = conflictList; } private String queryKey; private QueryService queryService; private LauncherView launcherView; public InstrumentedProcess(LauncherView launcherView, String label) { this.label = label; this.launcherView = launcherView; } public String toString() { return label; } @Override public int report(String type, String threadID, String conflictThreadID, String lock, String[] lockStack, String precedent, String[] precedentStack, String conflict, String[] conflictStack, String conflictPrecedent, String[] conflictPrecedentStack, String message) { final Conflict conflictItem = new Conflict(this, type, threadID, conflictThreadID, lock, lockStack, precedent, precedentStack, conflict, conflictStack, conflictPrecedent, conflictPrecedentStack, message); conflictList.add(conflictItem); ConflictHandler handler = new ConflictHandler(launcherView, conflictItem); Display.getDefault().syncExec(handler); return handler.result; } protected Conflict[] getDisplayedConflicts() { String filtersString = InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID).get(IAgent.PREF_DISPLAY_FILTERS, launcherView.getDefaultFilters()); String[] filters = filtersString.split(";"); Pattern[] patterns = new Pattern[filters.length]; for (int i = 0; i < filters.length; i++) { patterns[i] = Pattern.compile(filters[i]); } boolean showWarning = launcherView.shouldDisplayWarning(); ArrayList<Conflict> list = new ArrayList<Conflict>(); for (Conflict conflict : conflictList) { if (!showWarning && !conflict.isError()) continue; boolean passFilters = true; for (Pattern pattern : patterns) { if (pattern.matcher(conflict.conflict).matches() || pattern.matcher(conflict.precedent).matches()) { passFilters = false; break; } } if (passFilters) list.add(conflict); } return list.toArray(new Conflict[0]); } private ArrayList<Conflict> conflictList = new ArrayList<Conflict>(); public void setReportKey(String reportKey) { this.reportKey = reportKey; } public void setQueryKey(String queryKey) { this.queryKey = queryKey; } public void downloadGlobalLockState() { FileDialog dialog = new FileDialog(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell(), SWT.SAVE); dialog.setFileName(label + ".lockState"); final String filePath = dialog.open(); if (filePath == null) return; try { new ProgressMonitorDialog(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell()).run(true, true, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { XMLMemento root = XMLMemento .createWriteRoot("locks"); ITransaction transaction = null; try { IMemento locksRoot = root.createChild("root"); HashMap<String, QueryService.IBundleInfo> plugins = new HashMap<String, QueryService.IBundleInfo>(); transaction = queryService.createTransaction(); if (transaction == null) return; int count = transaction.getLockCount(); monitor.beginTask("Saving state...", count); int index = 0; int interval = 100; while (index < count) { ILock[] tmp = transaction.getLocks(index, Math.min(index + interval, count)); monitor.worked(tmp.length); for (int i = 0; i < tmp.length; i++) { XMLUtil.write(locksRoot, tmp[i]); String[] stackTrace = tmp[i].getStackTrace(); if (stackTrace.length > 0) { QueryService.IBundleInfo bundle = transaction.getBundleInfo(tmp[i]); if (!plugins.containsKey(bundle.getName())) plugins.put(bundle.getName(), bundle); } } index += interval; if (monitor.isCanceled()) break; } XMLUtil.write(root, plugins.values()); } finally { if (transaction != null) transaction.close(); } File file = new File(filePath); if (file.exists()) file.delete(); try { FileWriter writer = new FileWriter(file); root.save(writer); writer.close(); } catch (IOException e) { e.printStackTrace(); } monitor.done(); } }); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } finally { } } public void displayStatistics() { final ITransaction[] transactions = new ITransaction[1]; final ArrayList<StatisticsDialog.Row> locks = downloadLocks(transactions); if (locks.size() != 0) { StatisticsDialog dialog = new StatisticsDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), locks.toArray(new StatisticsDialog.Row[0]), transactions[0]); dialog.open(); } } private ArrayList<StatisticsDialog.Row> downloadLocks(final ITransaction[] transactions) { final ArrayList<StatisticsDialog.Row> locks = new ArrayList<StatisticsDialog.Row>(); if (!queryService.isConnected()) { try { new ProgressMonitorDialog(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell()).run(true, true, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { while (!queryService.isConnected()) { if (Display.getDefault() .readAndDispatch()) Thread.sleep(100); if (monitor.isCanceled()) break; } } }); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } if (queryService.isConnected()) { if (!queryService.isClosed()) { try { new ProgressMonitorDialog(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell()).run( true, true, new DownloadRunnable(transactions, locks)); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } if (locks.size() == 0) MessageDialog .openError(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell(), "Can't retrieve process information", "Process need to be running to get lock information."); else { StatisticsDialog dialog = new StatisticsDialog(PlatformUI .getWorkbench().getActiveWorkbenchWindow() .getShell(), locks.toArray(new StatisticsDialog.Row[0]), transactions[0]); dialog.open(); } } return locks; } public void setQueryService(QueryService queryService) { this.queryService = queryService; } public IService getQueryService() { return queryService; } public ArrayList<Conflict> getConflictList() { return conflictList; } }