/*******************************************************************************
* Copyright (c) 2010, 2014 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
*******************************************************************************/
package org.eclipse.tcf.internal.debug.ui.model;
import java.util.Map;
import org.eclipse.tcf.protocol.IToken;
import org.eclipse.tcf.protocol.Protocol;
import org.eclipse.tcf.services.ISymbols;
import org.eclipse.tcf.util.TCFDataCache;
public class TCFNodeSymbol extends TCFNode {
private final TCFData<ISymbols.Symbol> context;
private final TCFData<String[]> children;
private final TCFData<Map<String,Object>> location;
private int update_policy;
private ISymbolOwner owner;
private TCFNodeSymbol prev;
private TCFNodeSymbol next;
private static final int MAX_SYMBOL_COUNT = 64;
private static TCFNodeSymbol sym_list;
private static int sym_count;
private static boolean gc_posted;
protected TCFNodeSymbol(final TCFNode parent, final String id) {
super(parent, id);
context = new TCFData<ISymbols.Symbol>(channel) {
@Override
protected boolean startDataRetrieval() {
ISymbols syms = launch.getService(ISymbols.class);
if (id == null || syms == null) {
set(null, null, null);
return true;
}
command = syms.getContext(id, new ISymbols.DoneGetContext() {
public void doneGetContext(IToken token, Exception error, ISymbols.Symbol sym) {
set(token, error, sym);
if (error != null || sym == null) setUpdatePolicy(null, 0);
else setUpdatePolicy(sym.getOwnerID(), sym.getUpdatePolicy());
}
});
return false;
}
};
children = new TCFData<String[]>(channel) {
@Override
protected boolean startDataRetrieval() {
ISymbols syms = launch.getService(ISymbols.class);
if (id == null || syms == null) {
set(null, null, null);
return true;
}
command = syms.getChildren(id, new ISymbols.DoneGetChildren() {
public void doneGetChildren(IToken token, Exception error, String[] ids) {
set(token, error, ids);
}
});
return false;
}
};
location = new TCFData<Map<String,Object>>(channel) {
@Override
protected boolean startDataRetrieval() {
ISymbols syms = launch.getService(ISymbols.class);
if (id == null || syms == null) {
set(null, null, null);
return true;
}
command = syms.getLocationInfo(id, new ISymbols.DoneGetLocationInfo() {
@Override
public void doneGetLocationInfo(IToken token, Exception error, Map<String,Object> props) {
set(token, error, props);
}
});
return false;
}
};
setUpdatePolicy(null, 0);
if (sym_list == null) {
prev = next = this;
}
else {
prev = sym_list;
next = sym_list.next;
prev.next = next.prev = this;
}
sym_list = this;
if (!gc_posted) {
// Garbage collection: dispose unused symbols
gc_posted = true;
Protocol.invokeLater(5000, new Runnable() {
public void run() {
gc_posted = false;
int cnt = sym_count / 16;
while (sym_count > MAX_SYMBOL_COUNT) {
TCFNodeSymbol s = sym_list.next;
if (s.context.isPending()) break;
if (s.children.isPending()) break;
s.dispose();
if (cnt == 0) break;
cnt--;
}
if (sym_count > 0) {
gc_posted = true;
Protocol.invokeLater(5000, this);
}
}
});
}
sym_count++;
}
@Override
public void dispose() {
assert !isDisposed();
if (owner != null) {
owner.removeSymbol(this);
owner = null;
}
if (sym_list == this) sym_list = prev;
if (sym_list == this) {
sym_list = null;
}
else {
prev.next = next;
next.prev = prev;
}
prev = next = null;
sym_count--;
assert (sym_count == 0) == (sym_list == null);
super.dispose();
}
private void moveUp() {
if (sym_list != this) {
prev.next = next;
next.prev = prev;
prev = sym_list;
next = sym_list.next;
prev.next = next.prev = this;
sym_list = this;
}
}
public TCFDataCache<ISymbols.Symbol> getContext() {
moveUp();
return context;
}
public TCFDataCache<String[]> getChildren() {
moveUp();
return children;
}
public TCFData<Map<String,Object>> getLocation() {
moveUp();
return location;
}
private void setUpdatePolicy(String id, int policy) {
update_policy = policy;
if (!isDisposed()) {
TCFNode n = model.getNode(id);
if (!(n instanceof ISymbolOwner)) n = parent;
if (n != owner) {
if (owner != null) owner.removeSymbol(this);
owner = (ISymbolOwner)n;
owner.addSymbol(this);
}
}
}
void onMemoryMapChanged() {
context.reset();
children.reset();
location.reset();
}
void onExeStateChange() {
if (update_policy == ISymbols.UPDATE_ON_MEMORY_MAP_CHANGES) return;
context.reset();
children.reset();
location.reset();
}
}