001: package gnu.mapping;
002:
003: public class RunnableClosure implements Runnable {
004: Object result;
005: CallContext context;
006: public Environment environment;
007:
008: // These are only used to when we need to override the parents' in/out/err
009: // in the child. This is not needed for normal RunnableClosure objects, but (say)
010: // when starting a repl in a new window. In that case we could do te
011: // in/out/err override in the 'action'. FIXME.
012: private InPort in;
013: private OutPort out;
014: private OutPort err;
015: Throwable exception;
016:
017: Procedure action;
018: String name;
019:
020: static int nrunnables = 0;
021:
022: public String getName() {
023: return name;
024: }
025:
026: public void setName(String name) {
027: this .name = name;
028: }
029:
030: public RunnableClosure(Procedure action, CallContext parentContext) {
031: this (action, parentContext, parentContext.getEnvironment());
032: }
033:
034: public RunnableClosure(Procedure action, CallContext parentContext,
035: Environment penvironment) {
036: setName("r" + nrunnables++);
037: this .action = action;
038: SimpleEnvironment env = Environment.make(getName(),
039: penvironment);
040: env.flags |= Environment.THREAD_SAFE;
041: env.flags &= ~Environment.DIRECT_INHERITED_ON_SET;
042: this .environment = env;
043: int n = parentContext.pushedFluidsCount;
044: for (int i = 0; i < n; i++) {
045: // If we're inside a fluid-let, then the child thread should inherit
046: // the fluid-let binding, even if it isn't accessed in the child until
047: // after the parent exits the fluid-let. Set things up so only the
048: // binding in the parent is restored, but they share until then.
049: Location loc = parentContext.pushedFluids[i];
050: Symbol name = loc.getKeySymbol();
051: Object property = loc.getKeyProperty();
052: if (name != null && loc instanceof NamedLocation) {
053: NamedLocation nloc = (NamedLocation) loc;
054: if (nloc.base == null) {
055: SharedLocation sloc = new SharedLocation(name,
056: property, 0);
057: sloc.value = nloc.value;
058: nloc.base = sloc;
059: nloc.value = null;
060: nloc = sloc;
061: }
062: int hash = name.hashCode()
063: ^ System.identityHashCode(property);
064: NamedLocation xloc = env.addUnboundLocation(name,
065: property, hash);
066: xloc.base = nloc;
067: }
068: }
069: }
070:
071: public RunnableClosure(Procedure action, Environment penvironment,
072: InPort in, OutPort out, OutPort err) {
073: this (action, CallContext.getInstance(), penvironment);
074: this .in = in;
075: this .out = out;
076: this .err = err;
077: }
078:
079: public RunnableClosure(Procedure action) {
080: this (action, CallContext.getInstance());
081: }
082:
083: /** Get the CallContext we use for this Thread. */
084: public final CallContext getCallContext() {
085: return context;
086: }
087:
088: public void run() {
089: try {
090: if (context == null)
091: context = CallContext.getInstance();
092: else
093: CallContext.setInstance(context);
094: context.curEnvironment = environment;
095: if (in != null)
096: InPort.setInDefault(in);
097: if (out != null)
098: OutPort.setOutDefault(out);
099: if (err != null)
100: OutPort.setErrDefault(err);
101: result = action.apply0();
102: } catch (Throwable ex) {
103: exception = ex;
104: }
105: }
106:
107: /** Get the result of running this {@code Runnable}.
108: * The result is a value or a thrown exception.
109: * Should be called after {#code run} finishes. */
110: Object getResult() throws Throwable {
111: Throwable ex = exception;
112: if (ex != null)
113: throw ex;
114: return result;
115: }
116:
117: public String toString() {
118: StringBuffer buf = new StringBuffer();
119: buf.append("#<runnable ");
120: buf.append(getName());
121: buf.append(">");
122: return buf.toString();
123: }
124: }
|