Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using a wrapper file to start JVM #623

Closed
lgoldstein opened this issue Apr 26, 2015 · 14 comments
Closed

Allow using a wrapper file to start JVM #623

lgoldstein opened this issue Apr 26, 2015 · 14 comments

Comments

@lgoldstein
Copy link
Contributor

The idea is to use a wrapper file to specify JVM startup configuration - similar to Tanuki. Attached as gist is a patch for the java/java.cc file that knows how to read such a file and replace the original argc/argv with the parsed ones. Open issues:

  • Need to modify scripts/osv/modules/api.py to accept a wrapper parameter
  • Need to pass the modified classpath to the started JVM - the attached code assumes a -cp command line option, but it seems like there is some other mechanism for it.
@nyh
Copy link
Contributor

nyh commented Apr 26, 2015

On Sun, Apr 26, 2015 at 3:34 PM, Lyor Goldstein [email protected]
wrote:

The idea is to use a wrapper file to specify JVM startup configuration -
similar to Tanuki http://wrapper.tanukisoftware.com/doc/english/.
Attached as gist https://gist.github.com/lgoldstein/b88f50619cb5fd872304
is a patch for the java/java.cc file that knows how to read such a file
and replace the original argc/argv with the parsed ones. Open issues:

My view is that java.so (java/java.cc) has one goal - namely to be
compatible as much as possible (or as much as desirable) with the Linux
"java" program. I think that any other features/improvements would be
better done in separate executables, not in java.so.

For example, what's preventing you, for example, from writing a new
executable, myjava.so, which does your argv transformation (exactly like in
your gist) and then calls java.so's main()? Is there a downside to that
approach?

Your myjava.so could then sit in a separate OSv "module" (apps/...) so only
images who want this feature will get it.

Nadav Har'El
[email protected]

@lgoldstein
Copy link
Contributor Author

Sounds like a good idea - is there some documentation / example that explains how such a myjava.so would work - mainly:

  • How do I invoke java.so's main() from myjava.so ?
  • How do I link into the image myjava.so as well as java.so during the build phase ?
  • How do I make sure that the image boots with myjava.so's main() instead of java.so one ?

Also, I have not been able to infer from the java.cc code how to set up the classpath - the code seems to ignore the -cp argument. How then is the classpath from the scripts/osv/modules/api.py being used to configure the JVM before launching ?

@nyh
Copy link
Contributor

nyh commented Apr 27, 2015

On Mon, Apr 27, 2015 at 7:47 AM, Lyor Goldstein [email protected]
wrote:

Sounds like a good idea - is there some documentation / example that
explains how such a myjava.so would work - mainly:

  • How do I invoke java.so's main() from myjava.so ?

One option is to used the traditional Linux dlopen(3) API.

A second option is to use the OSv-specific C++ API, for example (not tested:

auto lib = elf::get_program()->get_library("/java.so");
if (!_lib) {
abort("Failed to load /java.so");
}
auto main = lib->lookup<int (int, char**)>("main");
if (!_main) {
abort("No main() in /java.so");
}
main(argc, argv);

  • How do I link into the image myjava.so as well as java.so during
    the build phase ?

You can put this "myjava.so" thing into whatever application which needs
it, or as a separate module in apps/, and the application that needs it
will "require" it.

  • How do I make sure that the image boots with myjava.so's main()
    instead of java.so one ?

The boot only runs "/java.so" if you write that in the command line (or
some python script trick does it for you...). So all you need to do is
change that command line (possibly we need an option to change that python
trick to give it an alternative java executable's path).

Also, I have not been able to infer from the java.cc code how to set up
the classpath - the code seems to ignore the -cp argument. How then is
the classpath from the scripts/osv/modules/api.py being used to
configure the JVM before launching ?

The classpath is set after the JVM starts. java.cc does the minimum it
needs to do, and then runs the io.osv.RunJava code (see
java/runjava/src/main/java/io/osv/RunJava.java) which does most of the real
work.

RunJava.java used to be a nice, understandable, program, but unfortunately,
it no longer is - as it now contains tons of "isolation" stuff (to make it
easier to run multiple independent Java programs in parallel) which I can't
say I understand. But you can just use it as-is.

Nadav Har'El
[email protected]

@lgoldstein
Copy link
Contributor Author

The classpath is set after the JVM starts. java.cc does the minimum it
needs to do, and then runs the io.osv.RunJava code (see
java/runjava/src/main/java/io/osv/RunJava.java) which does most of the real
work.

It still does not explain how does the classpath setting from the scripts/osv/modules/api.py gets to RunJava.java.

Basically, what I would like to do is parse the wrapper configuration and then invoke the JVM startup code as if it has been invoked using the current manner. Can you point me to the relevant source files and also explain the flow - i.e., who calls whom - especially the classpath part.

Thanks

@lgoldstein
Copy link
Contributor Author

Spoke to soon - figured it out - I may need your help in incorporating the code correctly into OSV, but other than that I am good to go.

@lgoldstein
Copy link
Contributor Author

@nyh I have the code ready to go - can you send me more detailed instructions about:

  • How can I add/modify a Python script so that in my application module.py I can use something like this:
from osv.modules import api
api.require('javawrapper')

default = api.run_java_wrapper(verbose=False,path='/foo/bar/wrapper.conf',...etc...)
  • How can I have my (C++) code be compiled as part of the build script if I use image=java-wrapper ? Is it enough that I place a Makefile ? If so, where can I find an example for such a Makefile ?
  • How can I add a require('java') in my wrapper code (or something similar) that tells the build script that by requiring the wrapper, the java module should also be automatically built and added to the image ?
  • Where is the target location of the java.so library in the generated image configured ? Is there some way to look it up at build time ? How about at run time ?

@nyh
Copy link
Contributor

nyh commented Apr 28, 2015

On Tue, Apr 28, 2015 at 1:03 PM, Lyor Goldstein [email protected]
wrote:

@nyh https://github.com/nyh I have the code ready to go - can you send
me more detailed instructions about:

  • How can I add/modify a Python script so that in my application
    module.py I can use something like this:

from osv.modules import api
api.require('javawrapper')

default = api.run_java_wrapper(verbose=False,path='/foo/bar/wrapper.conf',...etc...)

You can see the existing run_java code and create variants of it in
scripts/osv/modules/api.py

Alternatively (and much more simply), if you just want to run one specific
Java program and don't need the multi-Java-program features of that python
script, you can just run "java.so" (or your different program) directly
with api.run() - you can see an example in apps/jetty/module.py.

  • How can I have my (C++) code be compiled as part of the build
    script if I use image=java-wrapper ? Is it enough that I place a
    Makefile ? If so, where can I find an example for such a Makefile ?

Create a directory apps/java-wrapper, and put a Makefile (how to compile)
and usr.manifest there. You can see a very simple example of how to do this
in apps/native-example.

  • How can I add a require('java') in my wrapper code (or something
    similar) that tells the build script that by requiring the wrapper, the
    java module should also be automatically built and added to the
    image ?

You put the "api.require('java')" command in module.py. You can see an
example of this in apps/jetty/module.py - the jetty module needs "java.so"
so it requires the java module as well.
When you use the api.run_java() tool, it will automatically
api.require("java") for you, by the way.

  • Where is the target location of the java.so library in the
    generated image configured ? Is there some way to look it up at build time
    ? How about at run time ?

This is in usr.manifest. For example, in apps/jetty/usr.manifest we have:

/jetty/start.jar: ${MODULE_DIR}/upstream/start.jar

This means that the upstream/start.jar in the module's directory will be
uploaded to "/jetty/start.jar" in the image.

Nadav Har'El
[email protected]

@lgoldstein
Copy link
Contributor Author

@nyh Create a directory apps/java-wrapper, and put a Makefile (how to compile) and usr.manifest there. You can see a very simple example of how to do this in apps/native-example.

  • The example is for a C file and mine is C++
  • I need to inherit the same C++ compilation switches as all the other applications - especially the -std=c++11 and the extra inclusions - otherwise I am getting:
javawrapper.cc:9:22: fatal error: osv/elf.hh: No such file or directory
 #include <osv/elf.hh>
  • Ditto in order to create a java-wrapper.so file - I would like to use the same switches as the ones used for java.so

@lgoldstein
Copy link
Contributor Author

you can just run "java.so" (or your different program) directly with api.run() - not really, I want to have a run_java_wrapper method (for various reasons).

You can see the existing run_java code and create variants of it in scripts/osv/modules/api.py done, but where do I tell it that the startup module is java-wrapper.so instead of java.so ? Also, how do I make sure the correct arguments in the correct order are passed to it ? I assume that eventually the run_java calls run(...) after having built the correct command line. I want the same, only for my wrapper code.

@wkozaczuk
Copy link
Collaborator

Is this issue still valid given we can run completely unmodified JVM including java executable as long as it is a PIE?

@phillaverdiere
Copy link

Is this still a problem? Is it resolved by #626?

@wkozaczuk
Copy link
Collaborator

wkozaczuk commented Nov 22, 2019

So-called "java wrapper" was created in the early days when OSv could run shared libraries only (regular 'bin/java' is typically a pie or position-dependent executable). In essence, it is a C++ app that is built as a SO file acts as a limited substitute of traditional bin/java. It also comes with various java code located in java-base and other java-* modules.

Now standard bin/java in Java 9 and versions onward have added many new parameters (and removed some) for example to support modules and many new things. The OSv java.cc has not been kept up to date. More importantly, starting with the release 0.54, OSv can run a completely unmodified version of java including standard bin/java. So, in my opinion, the OSv java wrapper has become irrelevant. There are some features like ballooning (see this) that used to be supported by this wrapper. But ballooning got disabled due to some problems.

I am guessing there are around 20 open issues related to the limitations of the java wrapper (just search issues with java in it). And possibly most of them are not relevant. It would be nice for someone to revisit them. I think @lgoldstein had authored many of them?

I am planning to write a new Wiki page that will document up-to-date Java support in OSv.

@wkozaczuk
Copy link
Collaborator

@phillaverdiere If you are looking for issues to contribute to, I will try to make a pass at open ones and mark some them with good first issue label.

@nyh
Copy link
Contributor

nyh commented Nov 24, 2019

As far as I see it, this is a very specfic feature request from @lgoldstein who wanted to run Java applications in a specific way (using a configuration file in a certain format). I think that if the original requester of a feature lost interest in it, and nobody else expressed similar interest, we can safely close it. Especially since this whole area (how to run Java code) significantly change in the last few years, as @wkozaczuk noted.

So I'm closing this issue. Feel free to reopen it if there's renewed interest in this feature.

@nyh nyh closed this as completed Nov 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants