/******************************************************************************* * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. * 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: * Wind River Systems - initial API and implementation * Anna Dushistova (MontaVista) - [246996] [tcf] NullPointerException when trying to copy the process * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tcf.rse *******************************************************************************/ package org.eclipse.tcf.internal.rse.processes; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.rse.core.subsystems.AbstractResource; import org.eclipse.rse.services.clientserver.IServiceConstants; import org.eclipse.rse.services.clientserver.processes.IHostProcess; import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; import org.eclipse.tcf.protocol.IToken; import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.services.ISysMonitor; import org.eclipse.tcf.services.ISysMonitor.SysMonitorContext; public class TCFProcessResource extends AbstractResource implements IHostProcess { public static final String PROP_PC_UTIME = "PCUTime"; //$NON-NLS-1$ public static final String PROP_PC_STIME = "PCSTime"; //$NON-NLS-1$ private final TCFProcessService rse_service; private final ISysMonitor tcf_service; private final TCFProcessResource prev; private final String id; private Throwable error; private ISysMonitor.SysMonitorContext context; private final List<Runnable> children_wait_list = new ArrayList<Runnable>(); private final HashMap<String,TCFProcessResource> children = new HashMap<String,TCFProcessResource>(); private boolean children_loading; private boolean children_loaded; private Throwable children_error; private boolean running_wait_list; private long timestamp; private final String[] propertyKeys = new String[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_COUNT]; { propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_EXENAME] = ISysMonitor.PROP_FILE; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_GID] = ISysMonitor.PROP_GROUPNAME; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_PID] = ISysMonitor.PROP_PID; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_PPID] = ISysMonitor.PROP_PPID; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_STATUS] = ISysMonitor.PROP_STATE; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_TGID] = ISysMonitor.PROP_TGID; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_TRACERPID] = ISysMonitor.PROP_TRACERPID; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_UID] = ISysMonitor.PROP_UID; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_USERNAME] = ISysMonitor.PROP_USERNAME; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_VMSIZE] = ISysMonitor.PROP_VSIZE; propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_VMRSS] = ISysMonitor.PROP_RSS; } private Map<String, Object> properties = new HashMap<String, Object>(); TCFProcessResource(TCFProcessService rse_service, ISysMonitor service, TCFProcessResource prev, String id) { this.rse_service = rse_service; this.tcf_service = service; this.prev = prev; this.id = id; } public String getID() { return id; } public String getParentID() { return (String)properties.get(ISysMonitor.PROP_PARENTID); } public TCFProcessService getService() { return rse_service; } public void invalidate() { assert Protocol.isDispatchThread(); error = null; context = null; } public boolean validate(final Runnable done) { assert Protocol.isDispatchThread(); if (error != null) return true; if (context != null) return true; tcf_service.getContext(id, new ISysMonitor.DoneGetContext() { public void doneGetContext(IToken token, Exception error, SysMonitorContext context) { TCFProcessResource.this.error = error; TCFProcessResource.this.context = context; timestamp = System.currentTimeMillis(); if (error != null) { properties = new HashMap<String,Object>(); } else { properties = new HashMap<String,Object>(context.getProperties()); if (prev != null && timestamp > prev.timestamp) { setPCProperty(PROP_PC_UTIME, ISysMonitor.PROP_UTIME); setPCProperty(PROP_PC_STIME, ISysMonitor.PROP_STIME); } // Conversions are necessary for sorting to work toLong(ISysMonitor.PROP_PID); toLong(ISysMonitor.PROP_PPID); toLong(ISysMonitor.PROP_UTIME); toLong(ISysMonitor.PROP_STIME); toLong(ISysMonitor.PROP_CUTIME); toLong(ISysMonitor.PROP_CSTIME); toLong(ISysMonitor.PROP_STARTTIME); toLong(ISysMonitor.PROP_ITREALVALUE); toBigInteger(ISysMonitor.PROP_CODESTART); toBigInteger(ISysMonitor.PROP_CODEEND); toBigInteger(ISysMonitor.PROP_STACKSTART); toBigInteger(ISysMonitor.PROP_WCHAN); } Protocol.invokeLater(done); } }); return false; } private void toLong(String name) { Number n = (Number)properties.get(name); if (n == null || n instanceof Long) return; properties.put(name, Long.valueOf(n.longValue())); } private void toBigInteger(String name) { Number n = (Number)properties.get(name); if (n == null || n instanceof BigInteger) return; properties.put(name, new BigInteger(n.toString())); } private void setPCProperty(String property, String name) { Object x = prev.properties.get(name); Object y = properties.get(name); if (x instanceof Number && y instanceof Number) { BigInteger nx = x instanceof BigInteger ? (BigInteger) x : new BigInteger(x.toString()); BigInteger ny = y instanceof BigInteger ? (BigInteger) y : new BigInteger(y.toString()); double d = ny.subtract(nx).doubleValue() / (timestamp - prev.timestamp); properties.put(property, d); } } public long getTimestamp() { return timestamp; } public Throwable getError() { assert Protocol.isDispatchThread(); return error; } public ISysMonitor.SysMonitorContext getContext() { assert Protocol.isDispatchThread(); return context; } // IHostProcess methods public String getAllProperties() { String result = ""; //$NON-NLS-1$ for (int i = 0; i < ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_COUNT; i++) { result = result + properties.get(propertyKeys[i]); if (i != ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_COUNT - 1) result = result + IServiceConstants.TOKEN_SEPARATOR; } return result; } public long getGid() { Number n = (Number)properties.get(ISysMonitor.PROP_UGID); if (n == null) return -1; return n.longValue(); } public String getLabel() { return Long.toString(getPid()) + " " + notNull(getName()); //$NON-NLS-1$ } public String getName() { return (String)properties.get(ISysMonitor.PROP_FILE); } public long getPPid() { Number n = (Number)properties.get(ISysMonitor.PROP_PPID); if (n == null) return -1; return n.longValue(); } public long getPid() { Number n = (Number)properties.get(ISysMonitor.PROP_PID); if (n == null) return -1; return n.longValue(); } public String getState() { return (String)properties.get(ISysMonitor.PROP_STATE); } public long getTgid() { Number n = (Number)properties.get(ISysMonitor.PROP_TGID); if (n == null) return -1; return n.longValue(); } public long getTracerPid() { Number n = (Number)properties.get(ISysMonitor.PROP_TRACERPID); if (n == null) return -1; return n.longValue(); } public long getUid() { Number n = (Number)properties.get(ISysMonitor.PROP_UID); if (n == null) return -1; return n.longValue(); } public String getUsername() { return (String)properties.get(ISysMonitor.PROP_USERNAME); } public long getVmRSSInKB() { Number rss = (Number)properties.get(ISysMonitor.PROP_RSS); Number psz = (Number)properties.get(ISysMonitor.PROP_PSIZE); if (rss == null || psz == null) return 0; return (rss.longValue() * psz.longValue() + 1023) / 1024; } public long getVmSizeInKB() { Number vsz = (Number)properties.get(ISysMonitor.PROP_VSIZE); if (vsz == null) return 0; return (vsz.longValue() + 1023) / 1024; } public boolean isRoot() { return true; } private String notNull(String s) { return s == null ? "" : s; } String getStatusLine() { final String STATUS_DELIMITER = "|"; //$NON-NLS-1$ StringBuffer s = new StringBuffer(); s.append(getPid()).append(STATUS_DELIMITER); s.append(notNull(getName())).append(STATUS_DELIMITER); s.append(notNull(getState())).append(STATUS_DELIMITER); s.append(getTgid()).append(STATUS_DELIMITER); s.append(getPPid()).append(STATUS_DELIMITER); s.append('0').append(STATUS_DELIMITER); s.append(getUid()).append(STATUS_DELIMITER); s.append(notNull(getUsername())).append(STATUS_DELIMITER); s.append(getGid()).append(STATUS_DELIMITER); s.append(getVmSizeInKB()).append(STATUS_DELIMITER); s.append(getVmRSSInKB()).append(STATUS_DELIMITER); return s.toString(); } public Map<String,Object> getProperties() { return properties; } private void runChildrenWaitList() { assert !children_loading; assert children_loaded; try { running_wait_list = true; for (Runnable r : children_wait_list) r.run(); children_wait_list.clear(); } finally { running_wait_list = false; } } public Throwable getChildrenError() { return children_error; } public void flushChildrenCache() { Map<Long,TCFProcessResource> pid2res = rse_service.getProcessCache(); for (TCFProcessResource r : children.values()) { long pid = r.getPid(); if (pid > 0 && getPid() != pid) pid2res.remove(r.getPid()); } children_loaded = false; children_error = null; } public boolean loadChildren(Runnable run) { if (children_loaded) return true; assert !running_wait_list; children_wait_list.add(run); if (children_loading) return false; children_loading = true; try { final ISysMonitor m = rse_service.getTCFConnectorService().getSysMonitorService(); m.getChildren(getID(), new ISysMonitor.DoneGetChildren() { public void doneGetChildren(IToken token, Exception error, String[] ids) { try { if (error != null) { loadProcessesDone(error, null); } else if (ids == null) { loadProcessesDone(null, new TCFProcessResource[0]); } else { final TCFProcessResource[] arr = new TCFProcessResource[ids.length]; final Set<IHostProcess> pending = new HashSet<IHostProcess>(); for (int i = 0; i < ids.length; i++) { final TCFProcessResource r = new TCFProcessResource( rse_service, m, children.get(ids[i]), ids[i]); if (!r.validate(new Runnable() { public void run() { pending.remove(r); if (pending.isEmpty()) loadProcessesDone(null, arr); } })) pending.add(r); arr[i] = r; } if (pending.isEmpty()) loadProcessesDone(null, arr); } } catch (Throwable x) { loadProcessesDone(x, null); } } }); return false; } catch (Throwable x) { loadProcessesDone(x, null); return true; } } private void loadProcessesDone(Throwable error, TCFProcessResource[] arr) { assert children_loading; children_loading = false; children_loaded = true; children.clear(); if (arr != null && error == null) { Map<Long,TCFProcessResource> pid2res = rse_service.getProcessCache(); for (TCFProcessResource r : arr) { long pid = r.getPid(); if (pid > 0 && getPid() != pid) pid2res.put(pid, r); if (r.getError() == null) children.put(r.getID(), r); } } children_error = error; runChildrenWaitList(); } @Override public String toString() { return "[" + getStatusLine() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ } }