bugKawa - Bugs: bug #14098, runnable rfe

 
 

bug #14098: runnable rfe

Submitted by:  tk <huh>
Submitted on:  Thu 11 Aug 2005 09:19:45 PM UTC  
 
Category: Scheme librarySeverity: 3 - Normal
Item Group: Feature RequestStatus: Fixed
Privacy: PublicAssigned to: Per Bothner <bothner>
Open/Closed: Closed

Add a New Comment(Rich Markup)
   

You are not logged in

Please log in, so followups can be emailed to you.

 

Thu 25 Aug 2005 12:45:11 AM UTC, comment #5:

Thanks. I checked in this patch, with a few minor changes.

I didn't include the setIndirectDefines flag. You say it is
"closer" to 1.7 - but I don't think that was right.

We could add an optional 'shared' flag to the runnable function, just like the scheme-window function takes, but I don't think it should be the default. Also, I'm not convinced it's needed at all. If you disagree, perhaps you could post some use-cases on the mailing list so people can discuss it.

Per Bothner <bothner>
Project AdministratorIn charge of this item.
Mon 15 Aug 2005 07:15:41 PM UTC, comment #4:

Of course. your first suggestion of having Future encapsulate an
instance of RunnableClosure makes sense.

I've attached a patch that implements Future as such.

I slipped one change into RunnableClosure that you may disagree with.
The constructor calls setIndirectDefines on the closure's environment, so
that the behavior of future is closer to that of version 1.7.
I suppose one could argue that this should be done explicitly by
code that uses runnable.

tk <huh>
Mon 15 Aug 2005 08:41:38 AM UTC, comment #3:

Would it make sense for future to create a RunnableClosure that it passes to a Thread? Or perhaps Future could be a bare-bones class that does little more than extend Thread and create a RunnabeClosure. Or we could share code by calling shared static methods.

Per Bothner <bothner>
Project AdministratorIn charge of this item.
Fri 12 Aug 2005 03:44:58 PM UTC, comment #2:

Thanks for taking a look at this. I wasn't happy about the code
duplication either, but there are problems with your version.
The additional space overhead of using Thread is about a dozen
private fields, and the Thread constructor adds the instance to
the current ThreadGroup. This overhead may be small compared with
the creation of the RunnableClosure, but it's more than nothing.

There's also a more serious problem. While the thread stack isn't
created until start is called, in version 1.4 JVMs (at least) the
thread isn't removed from its ThreadGroup until the thread exits,
which it can't do without being started, so you're left with a
choice of leaking memory or having to allocate the stack and
scheduling the thread before it can be reclaimed. (I haven't
checked on whether 1.5 JVMs continue this hapless approach).

I'll look at whether there's another way to refactor it; if not I'd say
a little code duplication is worth avoiding the foregoing silliness.

tk <huh>
Fri 12 Aug 2005 06:00:01 AM UTC, comment #1:

I have a concern about the amound of duplication between RunnbaleClosure and Future. How would this hierarchy work:

public class RunnableClosure extends Thread
public class Future extends RunnableClosure

It might even be reasonable to just use the Future class instead of a new RunnableClosure class. Perhaps the runnable macro should just:
(define-syntax runnable
(syntax-rules ()
((future expression)
(make <gnu.mapping.Future> (lambda () expression)))))
I.e. same as Future but doesn't call start.
One issue is the name - what is printed. An idea: Change the toString method to print #<runnable " ... before start is called and #<future ... after.

Per Bothner <bothner>
Project AdministratorIn charge of this item.
Thu 11 Aug 2005 09:19:45 PM UTC, original submission:

In response to savannah bug #14072, following is a strawman implementation
of an api for creating a java.lang.Runnable from a procedure and its
environment. The implementation is based on Future.

Example usage that illustrates need for such an api:

(let ((graphics (invoke canvas 'getGraphics)))
(invoke-static <java.awt.EventQueue> 'invokeLater
(runnable
(lambda ()
(invoke graphics 'drawRect 0 0 1 1)))))

kawa/lib/runnable.scm:

(define (runnable (proc :: <procedure>)) :: <gnu.mapping.RunnableClosure>
(make <gnu.mapping.RunnableClosure> proc))

gnu/mapping/RunnableClosure.java:

package gnu.mapping;

public class RunnableClosure implements Runnable
{
Object result;
CallContext context;
public Environment environment;
Throwable exception;
Procedure action;
String name;
static int nrunnables=0;

public String getName() {
return name;
}

public void setName(String name) {
this.name=name;
}

public RunnableClosure (Procedure action, CallContext parentContext)
{
this(action, parentContext, parentContext.getEnvironment());
}

public RunnableClosure (Procedure action,
CallContext parentContext, Environment penvironment)
{
setName("r"+nrunnables++);
this.action = action;
SimpleEnvironment env = Environment.make(getName(), penvironment);
env.flags |= Environment.THREAD_SAFE;
env.flags &= ~Environment.DIRECT_INHERITED_ON_SET;
env.setIndirectDefines(); // note -- not in Future
this.environment = env;
int n = parentContext.pushedFluidsCount;
for (int i = 0; i < n; i++)
{
// If we're inside a fluid-let, then the child thread should inherit
// the fluid-let binding, even if it isn't accessed in the child until
// after the parent exits the fluid-let. Set things up so only the
// binding in the parent is restored, but they share utnil then.
Location loc = parentContext.pushedFluids[i];
Symbol name = loc.getKeySymbol();
Object property = loc.getKeyProperty();
if (name != null && loc instanceof NamedLocation)
{
NamedLocation nloc = (NamedLocation) loc;
if (nloc.base == null)
{
SharedLocation sloc = new SharedLocation(name, property, 0);
sloc.value = nloc.value;
nloc.base = sloc;
nloc.value = null;
nloc = sloc;
}
int hash = name.hashCode() ^ System.identityHashCode(property);
NamedLocation xloc = env.addUnboundLocation(name, property, hash);
xloc.base = nloc;
}
}
}

public RunnableClosure (Procedure action)
{
this(action, CallContext.getInstance());
}

public RunnableClosure (Procedure action, Environment penvironment)
{
this(action, CallContext.getInstance(), penvironment);
}

/** Get the CallContext we use for this Thread. */
public final CallContext getCallContext() { return context; }

public void run ()
{
try
{
if (context == null)
context = CallContext.getInstance();
else
CallContext.setInstance(context);
context.curEnvironment = environment;
result = action.apply0 ();
}
catch (Throwable ex)
{
exception = ex;
}
}

public String toString() {
StringBuffer buf = new StringBuffer();
buf.append ("#<runnable ");
buf.append(getName());
buf.append(">");
return buf.toString();
}
}

tk <huh>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach File(s):
   
   
Comment:
   

Attached Files
file #3367:  RunnableClosure.java added by huh (3KiB - application/octet-stream - gnu/mapping/RunnableClosure.java)
file #3366:  diff.rc added by huh (9KiB - application/octet-stream - cvs diff -u patch)

 

Depends on the following items: None found

Items that depend on this one: None found

 

CC list is empty

 

Do you think this task is very important?
If so, you can click here to add your encouragement to it.
This task has 0 encouragements so far.

Only logged-in users can vote.

 

Please enter the title of George Orwell's famous dystopian book (it's a date):

 

 

Follow 6 latest changes.

Date Changed By Updated Field Previous Value => Replaced By
Thu 25 Aug 2005 12:45:11 AM UTCbothnerStatusNone=>Fixed
  Assigned toNone=>bothner
  Open/ClosedOpen=>Closed
Mon 15 Aug 2005 07:16:46 PM UTChuhAttached File-=>Added RunnableClosure.java, #2828
Mon 15 Aug 2005 07:15:41 PM UTChuhAttached File-=>Added diff.rc, #2827
Thu 11 Aug 2005 09:19:45 PM UTChuhCarbon-Copy-=>Added -unavailable-

Back to the top


Powered by Savane 3.1-cleanup1