If you intend to use libjulia-clj with Julia and enable Julia’s threading mechanism then you probably should read this document :-). @mkitti and myself just did quite a deep dive into how the JVM and Julia deal with signals and figured out a middle path that allows both to coexist peacefully.
There is more to do here; I haven’t setup a way to get field values from a thing only call it as a function but, after waiting quite a while for diffeq to compile, it appears to work.
Speaking of which:
I should redirect logging to the normal logging pathways. Do you have an example of someone writing a custom logger? I had zero feedback during diffeq compilation and killed the process to try it from Julia then saw the log message.
Does Julia have an object-oriented way to override stderr/stdout or do they have to be C-files? In python I could implement an object and set that as std err and stdout and this really helps debugging things. Perhaps for Julia simply setting up logging correctly is fine; I just do not know.
I found how pyjulia manages stdout and stderr. I have a question about references and GC. The python code maintains the new stdout, stderr pipes in global variables. But the code also closes over them like such:
# At file scope
const read_stdout = Ref{Base.PipeEndpoint}()
# At local scope
global readout_task
read_stdout[], = redirect_stdout()
readout_task = @async pipe_stream(read_stdout[], out_receiver)
I could see the readout task needing to be global else the GC could clean it up but I do not understand why the read_stdout needs to be global. It is closed over in pipe_stream.
Not a big issues as I can just copy the code and it was written by people with a lot more Julia knowledge than I have. Just trying to get a feel for some of the more subtle issues of Julia GC.
My guess is that this code was originally from IJulia which is the Julia kernel for Jupyter Notebooks.
One reason to expose a global is so that the variable is accessible. It’s like a public property of a class in Java.
The reason for the constRef is actually a Julia idiom. globals can really slow things down in Julia because they mutate. A const Ref allows us to make sure that a global’s type stays consistent.
I think first I would like to figure out exactly what is going on with the task system. I can always read data out of the redirection pipe with readline or something like that. I tested this and it works.
But why the task never actually runs but reports that it did is something that I think is important. Perhaps it is a problem with my setup; not sure but I was hoping there was a clear answer or some global task error queue I could check.
@mkitti - I feel the task question deserves a new thread on discourse or on slack. What is the best way to elevate this question a bit? Or perhaps get a few more eyes on that specific question in this thread? I think it comes down to exactly how the @async macro is implemented as it feels to me like there is some interaction with ccall inside the macro. If the code is pure Julia code, everything works fine. As soon as I try to call back to clojure using a C fn ptr then async call fails.
Great question. I do not set that environment variable anywhere so it is left to be the default. I assume the ccall convention has to work but I can set the variable to zero and see.
This is a nice write-up about Tasks and Threads in Julia:
The ALWAYS_COPY_STACKS variable eventually came to be controlled by the JULIA_COPY_STACKS environmental variable. What I have figured out is that the JVM does not like the the Task mode where where the stack is not copied.
Also if you are actually multithreading on the Julia side, then you might need to be very careful about which what JNIENV pointers you are using since you need a different one per thread. The problem is that Julia Tasks were purposely designed to abstract the relationship to Threads, so you don’t really know what Thread a Task might be running on.
Hmm, perhaps the best way to do redirection is to call redirect_xxx and then get the raw libuv handle from the pipe and install a read callback on it using libuv. This sidesteps the task system entirely.
Trying to use your LibJulia library - I’m having trouble with first line of
jna.clj as it utilizes julia_clj.JLOptions
From leinegen repl I’m using -
(require '[libjulia-clj.julia :as julia])
What I’ve done -
Installed Julia 1.5.4, julia_home is set to point to the install directory
Used git to download LibJulia project
Used from LibJulia directory
lein repl
At user prompt used:
user> (require '[libjulia-clj.julia :as julia])
I’m getting:
Syntax error (ClassNotFoundException) compiling at (libjulia_clj\impl\jna.clj:1:1).
julia_clj.JLOptions
Note - I found that Julia 1.5.4 does have the Options.jl library. My path for
julia_home is pointing to Julia 1.5.4 install directory. I have not checked for
later Julia install on my system. My julia_home is set to point to Julia 1.5.4
install directory.