anyone know of a way to check at runtime if you're running inside a native image vs on a regular JVM?
https://github.com/lread/clj-graal-docs#writing-graalvm-specific-code
perfect! thanks!
took a lot of trial and error but I managed to get funnel to daemonize/background itself
some gnarly JNI shenanigans... still need to clean this up but might do a write-up later
actually the thing that took the most time was trying to somehow statically include my native code in the final executable, because it's just one tiny function, it seemed so silly to have to distribute a separate .so for that... tried all kinds of linker options and read tons of stuff online until finally decided that it can't be done π then figured out a great hack around it. Include the .so
as a resource, copy it to the filesystem when starting up and then load it from there
sounds pretty nifty!
so for linux you have .so
, macos .dylib
, and windows .dll
and choose among them at runtime?
@plexus If you are going to do a writeup, might want to also put it in clj-graal-docs
oh yes, that would be nice
@plexus The resource hack has already been done before as part of spire, https://github.com/borkdude/clojure-rust-graalvm and some others
Spire was the first one that did it I think
Here's some Clojure code which illustrates it: https://github.com/borkdude/clojure-rust-graalvm/blob/044ef3c921e7b2c9058e431a62574d85b1079011/clojure/src/clj_rust/core.clj#L10
mmm, lacking .dll
π
I leave .dll as an exercise to the reader ;)
he he π
This is only a POC
a very nice one at that π©
The background / daemonizing I would be interested to see
Here are already some docs about interacting with native libraries: https://github.com/lread/clj-graal-docs#interfacing-with-native-libraries
yeah haven't gotten to the macos part yet, since I don't have access to a mac.
@plexus CircleCI and Github Actions have so that should not be too hard to get around
I know, but for debugging that's not very helpful
CircleCI offers ssh access
Not too long ago I didn't have access to Windows so I debugged everything on appveyor. A bit tedious but it works. Having SSH access makes all the difference for getting fast feedback though.
You might want to poke @marc-omorain for macOS access if it's not enabled for your open source project yet, if you go with CircleCI
π
this is the one project where we're using GH actions actually, although generally my intention is to migrate towards GH actions for the other LI projects as well
https://github.com/lambdaisland/funnel/commit/be69644044f632b91d41a4f22062f20eb7da5104
Impressive, so you're using C to daemonize the Graal process
what's this for?
if ((chdir("/")) < 0) {
exit(EXIT_FAILURE);
}
some code I cargo culted from this example http://jnicookbook.owsiak.org/recipe-no-029/ as far as I understand it changes the working directory of the process to "/", which I'm guessing is so that it becomes independent of the location where it was started, for instance if the directory it was started from gets deleted
yeah it's really just using JNI so I can do fork
+ setsid
what if the process doesn't have permission to chdir to /
?
then I suppose it fails. When would that be the case though?
don't know :)
does daemonize/chdir/etc also work via JNI in the JVM?
I've been considering some function in babashka to do this, but the JVM itself doesn't support this
ls -ld /
drwxr-xr-x 21 root root 4096 Jun 1 12:43 /
read+execute permissions globally, I'm guessing that's pretty standard
does chdir("/")
also work on Windows with the forward slash?
you could in theory do the same thing on the JVM, but I believe it's not considered safe. It may also not be safe in this case, time will tell
re. windows, probably not. I'm not doing windows builds at this point.
https://blog-old.headius.com/2009/05/fork-and-exec-on-jvm-jruby-to-rescue.html > Update: The biggest problem with using fork+exec in this way is that you can't guarantee nothing happens between the fork call and the exec call. If, for example, the JVM decides to GC or move memory around, you can have a fatal crash at the JVM process level. Because of that, I don't recommend using fork + exec via FFI in JRuby, even though it's pretty cool.
hmmm
I guess you can also just run funnel &
?
yes, but then it's not detached from the parent shell process. If you close the shell it will kill the child
I think you could do nohup funnel &
I guess you can install funnel as a service, systemd kind of thing?
yes, totally
the direction I'm going now is that tools like kaocha-cljs2 that need it will try starting it in the background. If there's already one running then it's a no-op.
although at this point I'd like users to install and run it themselves, so they know it exists, since it's a good place to look when troubleshooting
@plexus I guess you can also use java.lang.ProcessBuilder to run one in the background, without daemonizing
each test run would then have to run its own instance
or rely on some pid file or something to check if there's already one
but then it would only live as long as the test runner process, that defeats the purpose
> Funnel provides persistence and discoverability. It keeps connections to long lived processes (like a browser), so that short-lived processes (like a test runner) can discover and interact with them . This is why we recommend running Funnel as a separate long-lived process, rather than for instance embedding it into the tool that uses it.
If you start a subprocess from a Java process the child isnβt terminated when parent exits - thatβs a typical behavior in Linux