calling a nestedvm class method from another class

26 views
Skip to first unread message

Ron

unread,
Jun 30, 2007, 2:18:22 PM6/30/07
to NestedVM
I'm trying to understand how to call Runtime.start.
If I do start(args) I get a arrayindexoutofboundsexception.
There is another start method that takes two arguments,
public final void start(String[] args, String[] environ)

Is this the one I use instead of the single arg version?
What goes in the two params?

Brian Alliet

unread,
Jun 30, 2007, 3:05:01 PM6/30/07
to Ron, NestedVM
On Sat, Jun 30, 2007 at 06:18:22PM -0000, Ron wrote:
> I'm trying to understand how to call Runtime.start.
> If I do start(args) I get a arrayindexoutofboundsexception.

Hmm.. can you send the first few lines of the stack trace?

> There is another start method that takes two arguments,
> public final void start(String[] args, String[] environ)

This is if you want to set the initial environment for your process.
environ should be a series of strings of the form "ENVVAR=value". This
is optional though. Plain old start(String[] args) or even start()
should work.

-Brian

Ron

unread,
Jun 30, 2007, 4:30:26 PM6/30/07
to NestedVM
org.ibex.nestedvm.Runtime$FaultException:
java.lang.ArrayIndexOutOfBoundsExcepti
on: 468503 at (unknown)
at subdue._execute(subdue.mips)
at org.ibex.nestedvm.Runtime.__execute(Runtime.java:506)
at org.ibex.nestedvm.Runtime.call(Runtime.java:679)
at org.ibex.nestedvm.Runtime.call(Runtime.java:648)
at org.ibex.nestedvm.Runtime.call(Runtime.java:632)
at SubdueCaller.main(SubdueCaller.java:13)
Process exited on signal 11
org.ibex.nestedvm.Runtime$CallException: Process exit()ed while
servicing a call
() request
at org.ibex.nestedvm.Runtime.call(Runtime.java:683)
at org.ibex.nestedvm.Runtime.call(Runtime.java:648)
at org.ibex.nestedvm.Runtime.call(Runtime.java:632)
at SubdueCaller.main(SubdueCaller.java:13)

Brian Alliet

unread,
Jun 30, 2007, 6:33:48 PM6/30/07
to Ron, NestedVM
On Sat, Jun 30, 2007 at 08:30:26PM -0000, Ron wrote:
> org.ibex.nestedvm.Runtime$FaultException:
> java.lang.ArrayIndexOutOfBoundsExcepti
> on: 468503 at (unknown)

This means your app application is crashing. Does it work when you just
run it normally? All the generated main does is invoke Runtime.run, and
the first thing Runtime.run does is invoke start. I'm not sure what is
different about how you're invoking start. Are you passing the same
arguments to start as you pass when you run your app from the command
line? Maybe you're forgetting argv[0], which should be the name of the
app (main tacks this on for you but start expects you to do it).

-Brian

Ron

unread,
Jun 30, 2007, 9:44:45 PM6/30/07
to NestedVM
I'm trying to do the traditional argc/argv thing.
How can I use call to pass a valid argc and argv?
None of the versions of call that I see is made to
do that.

Brian Alliet

unread,
Jul 1, 2007, 9:46:58 AM7/1/07
to Ron, NestedVM
On Sun, Jul 01, 2007 at 01:44:45AM -0000, Ron wrote:
> I'm trying to do the traditional argc/argv thing.
> How can I use call to pass a valid argc and argv?
> None of the versions of call that I see is made to
> do that.

I was talking about *start*, not call. You pass argv to start. Looking
at your message again, it looks like you got the start() part right, as
your app is failing in call().

So the basic sequence is:

rt.start(new String[]{"subdue","arg1","arg2"}); // argv args
rt.execute();
rt.call("foo",1,2,3); // where 1,2,3 are args to the function foo

Would you mind posting the source code for SubdueCaller and the C type
signatures for the functions you're trying to call. This would make it
a while lot easier to see what is going on. The C source code would be
even better, but I know some people are using NestedVM stuff they can't
release.

-Brian

Ron

unread,
Jul 1, 2007, 12:43:58 PM7/1/07
to NestedVM
If I had an 'hello world' program in C, that
would print the value of argc and all of the values in argv
using the value of argc as a count of how many values to print,
how would I call that nestedvm generated class from another
class?

My understanding of the example you gave me
doesn't cover passing argc. It would make re-using existing
C programs much easier if there was a version of call to handle
this common scenario of argc/argv.

It's that straight forward an issue I think. Do any of the
versions of call handle this simple case? This is what
all C programs start out with for parameters. Many C programs
count on a valid value for argc, right? The signature of
the called program fuction I'm using is the same as a normal c main
function,
(int argc, char **argv).

The error is simply don't understand how to
pass a valid argc/argv parameter set to a 'main' function.

Brian Alliet

unread,
Jul 1, 2007, 1:27:23 PM7/1/07
to Ron, NestedVM
I think you may actually be making things more complicated than they
need to be. I might've misunderstood what you were originally asking
and just confused you more with the call stuff.

On Sun, Jul 01, 2007 at 04:43:58PM -0000, Ron wrote:
> If I had an 'hello world' program in C, that
> would print the value of argc and all of the values in argv
> using the value of argc as a count of how many values to print,
> how would I call that nestedvm generated class from another
> class?

This one is easy. If you just want to run a NestedVM binary, that is,
pass some command line arguments and get the return code you don't need
call() at all. There is a method, run(), that does exactly that:

Runtime rt = new subdue();
int return_code = rt.run(new String[]{"subdue"/*argv[0]*/,"arg1","arg2"});
System.out.println("Process exited with: " + return_code);

> My understanding of the example you gave me
> doesn't cover passing argc. It would make re-using existing
> C programs much easier if there was a version of call to handle
> this common scenario of argc/argv.

Let me try to explain the call() stuff again (and feel free to ignore
this if run() does what you need, you don't need call() in this case).

The C main has no run no matter what. Even if all you ever intend to do
with your app is call random functions from java you still need to
"startup" the application normally. The C runtime has to do some
startup stuff and in the C++ case, constructors executed, etc.

start() gets ready to do just that. You pass it argv (and maybe an
environment) and it gets nestedvm ready to start your application (but
doesn't actually do it yet). Next, execute() runs the app. This would
actually execute all the startup code and eventually call main() with
the argv you supplied to start.

Runtime rt = new myapp();
rt.start(new String[]{"myapp","arg1","arg2"});
boolean i_have_exited = rt.execute();

Now control is in the hands of your C application. You can do whatever
you want in C then either exit the application (either by returning
from main or calling exit) or "pause" it. Either way, control then
returns to java, and the execute() method returns.

If you exited in C, then you can call the exitStatus() method to obtain
the exit status, aside from that the Runtime object is pretty much
useless at this point.

// normally you don't need this as you know what your app does in main
if(i_have_exited) {
System.err.println("Exited with: " + rt.exitStatus());
}

However, if you "paused" from C (by calling the _pause() function in C)
you can now use the call() method. Call will invoke individual
functions in C and pass them arguments. You don't want to call main()
again here since it is already running (it is sitting waiting for the
pause function to return).

else {
int hello_world = rt.strdup("Hello World");
rt.call("puts",hello_world);
rt.free(hello_world);
}

If you happen to want to invoke a method with a type signature like
main via call there isn't any method like start() that'll pack up an
array of strings for you. You'd have to roll your own (but
Runtime.{malloc,strdup,memRead,memWrite} will make this pretty easy)

/* say we have foo(char **blah); */
int array = rt.malloc(4/*sizeof(char*)*/*3);
for(i=0;i<3;i++)
memWrite(array+i*4,rt.strdup("blah: "+i));
rt.call("foo",array);
for(i=0;i<3;i++) rt.free(memRead(array+i*4));
rt.free(array);

Ron

unread,
Jul 1, 2007, 2:03:52 PM7/1/07
to NestedVM
Thanks for your patience Brian!

The approach I've tried to take is to rename main
to foo_main(int argc, char **argv),
and call it after creating a main that only has
_pause in it. So I can use:

Runtime rt = new subdue();
int return_code = rt.run(new String[]{"subdue"/
*argv[0]*/,"arg1","arg2"});
System.out.println("Process exited with: " + return_code);

to call my new foo_main? If it doesn't set argc, it won't work for me.
Let's say I have 5 related standalone c programs. I want to combine
them into one nestedvm class that will allow me to call any one of
them one or
more times before exiting my program. Since this is a family of
utility programs, it would be more efficient to combine them for size
reasons.

I think the _pause method is required rather than the run example you
described?

Brian Alliet

unread,
Jul 1, 2007, 3:31:34 PM7/1/07
to Ron, NestedVM
On Sun, Jul 01, 2007 at 06:03:52PM -0000, Ron wrote:
> to call my new foo_main? If it doesn't set argc, it won't work for me.

Ah.. I see. In that case, take a look at that last example:

> > /* say we have foo(char **blah); */
> > int array = rt.malloc(4/*sizeof(char*)*/*3);
> > for(i=0;i<3;i++)
> > memWrite(array+i*4,rt.strdup("blah: "+i));
> > rt.call("foo",array);
> > for(i=0;i<3;i++) rt.free(memRead(array+i*4));
> > rt.free(array);

You could adapt this a little to write:

public static int call_mainish(Runtime rt, String name, String[] args) {
// allocate memory for the argv array
int argv = rt.malloc((args.length+1)*4);
// stick the app name in argv[0]
rt.memWrite(argv,rt.strdup(name));
// stick the arguments in the remaining slots
for(int i=0;i<args.length;i++)
rt.memWrite(argv+(i+1)*4,rt.strdup(args[i]));
// call the main-ish funchion with argc and argv
int return_code = rt.call(name + "_main",args.length + 1, argv);
// free everything
for(i=0;i<args.length+1;i++)
rt.free(rt.memRead(argv+i*4));
rt.free(argv);
// return
return return_code;
}

(this code isn't tested at all, but should be close)

Another option which may be a little easier (and is how I've done this
kind of thing) is to have your C main function dispatch based on the
app name:

int main(int argc,char **argv) {
if(strcmp(argv[0],"foo")==0) return foo_main(argc,argv);
if(strcmp(argv[0],"bar")==0) return bar_main(argc,argv);
if(strcmp(argv[0],"baz")==0) return baz_main(argc,argv);
return EXIT_FAILURE;
}

So to run foo you'd do:

int rc = rt.run(new String[]{"foo","foo's arg"});

and bar:

int rc = rt.run(new String[]{"bar","foo's arg"});

etc.

-Brian

Ron

unread,
Jul 2, 2007, 9:29:02 AM7/2/07
to NestedVM
I want to be able to call foo, bar or baz more than once, I don't
want to exit after calling one of them. I think I have to use
call, don't I? I need call, with a way to pass the argc int parameter,
then an array of strings. The examples show me how to do call and
get argv set up, but not argc. I guess I could change all of the
C programs to figure out what argc is, but it seems a shame to
have to modify a lot of programs, when all standard C programs have a
main
with the same signature already. I really appreciate the help!

Brian Alliet

unread,
Jul 2, 2007, 9:49:58 AM7/2/07
to Ron, NestedVM
Look at the call_mainish example function I have below. That passes
both argc and argv (argc is easy, it is just args.length + 1 below).

You're right. If you don't want to exit between the calls then you need
to use call, not run, however, the startup cost might be low enough
that this doesn't matter much.

-Brian

Ron

unread,
Jul 2, 2007, 11:54:23 AM7/2/07
to NestedVM
I get this error:

java.lang.IllegalStateException: call() called in inappropriate state

Here's the code, it bombs on the first rt.malloc call:

import org.ibex.nestedvm.UnixRuntime;

public class SubdueCaller
{


public static void main(String [] args)
{
org.ibex.nestedvm.Runtime rt = new subdue();
call_mainish(rt,"subdue_main",args);
}


public static int call_mainish(org.ibex.nestedvm.Runtime rt, String
name, String[] args) {
int return_code=0;
try{


// allocate memory for the argv array
int argv = rt.malloc((args.length+1)*4);
// stick the app name in argv[0]
rt.memWrite(argv,rt.strdup(name));
// stick the arguments in the remaining slots
for(int i=0;i<args.length;i++)
rt.memWrite(argv+(i+1)*4,rt.strdup(args[i]));
// call the main-ish funchion with argc and argv

return_code = rt.call(name + "_main",args.length + 1, argv);
// free everything

for(int i=0;i<args.length+1;i++)
rt.free(rt.memRead(argv+i*4));
rt.free(argv);
// return
}catch(Exception e)
{
e.printStackTrace();
}
return return_code;

Ron

unread,
Jul 2, 2007, 2:24:44 PM7/2/07
to NestedVM
I figured out that I need to call rt.start() first.
It runs correctly now, thanks!
Reply all
Reply to author
Forward
0 new messages