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

Why reply register a SignalHandler when connect to remote nREPL server #127

Open
chunlinyao opened this issue Oct 16, 2013 · 9 comments
Open

Comments

@chunlinyao
Copy link

Reply register a SignalHandler when connect to a remote nREPL server. this cause Signal class hold a function from Clojure and can not unload all Clojure related classes and CassLoaders. I think the INT signal only should be handled in the client side. why this code is required?

https://github.com/trptcolin/reply/blob/master/src/clj/reply/eval_modes/nrepl.clj#L246

I'am writing a project which inject a nREPL server into other java process by pid. I want to unload all Clojure related classes which is loaded by a custom ClassLoader, But I found Signal hold the GC root. register SignalHandler.SIG_DFL can fix it.

@trptcolin
Copy link
Owner

That's a good question. I had to dig around in the git history a bit to remember the answer, and luckily my past self explained it in a commit message. Basically when I had nREPL running in the same process but different classloader, the whole process would exit on INT signals because of the default signal handler.

But based on your suggestion, I wonder if we could use SignalHandler.SIG_IGN instead and have everything work? http://srcrr.com/java/oracle/openjdk/6/reference/sun/misc/SignalHandler-source.html

@chunlinyao
Copy link
Author

Can we distinguish between the same process nREPL server and remote nREPL server, and only replace signal handler for the same process situation. Than we can let remote server keep default signal handlers. SignalHandler.SIG_IGN can make the classloader which running nREPL unloadable.

@tobias
Copy link
Contributor

tobias commented Nov 19, 2013

@trptcolin - is this the issue you mentioned to me outside the cupcake place? :)

We're seeing the same issue for folks using reply to connect to an Immutant process. Ideally, it would be nice to know when we are connecting to a remote nrepl vs. back into the same process, but I don't see an easy way to do that.

@trptcolin
Copy link
Owner

@tobias yep this is the one.

We could easily solve a subset of this problem: when REPLy itself is responsible for starting up the nREPL server. Since we know enough to start the server, we could omit the signal handler whenever we don't start the server.

It seems like that's not enough for the usual case, where lein starts up the nREPL server. But maybe with some investigation it'll turn out that either my memory of the initial problem (the server side exiting) is wrong, or things have changed enough to eliminate it. Otherwise, maybe an option when starting REPLy that lets it know the server is in the same process? Though that seems pretty hacky...

trptcolin added a commit that referenced this issue Feb 21, 2014
Looks like something else has changed since
4497310 to make this unnecessary. Yay!

refs #127, 133
@trptcolin
Copy link
Owner

OK, I finally got a chance to look at this, and it looks like the reason I had this code there initially is no longer valid. Any help testing (especially on Windows) would be appreciated, but this does seems to be working for me on master.

@trptcolin
Copy link
Owner

I can't find any evidence on my VM that ctrl-c actually works at all in a Windows lein repl, even before this change. For now I'm going to have to leave it to people who actually use Windows to try things out and submit issues/patches if things are broken.

@trptcolin trptcolin reopened this Jun 18, 2014
@trptcolin
Copy link
Owner

I was wrong. This causes brokenness on lein 2.4.2 when running inside a project (works fine outside of one, which must have been where I tested):

clj16.core=> (while true (+ 1 2 3))
Exception in thread "Thread-3" clojure.lang.ExceptionInfo: Subprocess failed {:exit-code 130}
        at clojure.core$ex_info.invoke(core.clj:4403)
        at leiningen.core.eval$fn__4770.invoke(eval.clj:236)
[... etc ...]

So I'm re-opening this so I remember to address it, but I'm wondering if the fix just belongs in lein - since the nrepl server subprocess is what dies, and lein is responsible for spinning that up, maybe lein should either (a) disconnect the server subprocess from the STDIN stream somehow or (b) register a no-op SIGINT handler.

@trptcolin
Copy link
Owner

Ah, we're already attempting to disconnect from STDIN for the server subprocess. So I guess doing (b) in leiningen itself is the best idea I've got.

trptcolin added a commit to technomancy/leiningen that referenced this issue Jun 18, 2014
Unfortunately, even though *pump-in* is false, the server subprocess
still gets the SIGINT when you hit <ctrl-c>. REPLy used to take care of
that by registering a handler itself, but it's a ClassLoader leak, as
discussed in trptcolin/reply#127, so I removed it. But now subprocess
servers crash instead of gracefully being interrupted.

Here we're careful only to register the process in the specific case
where we're responsible for both the input and the server.

Pro: REPLy clients avoid classloader leaks.
Con: All REPLy clients have to implement this same sort of handling, but
only (?) if they're running in a subprocess.
@vemv
Copy link

vemv commented Jan 19, 2021

Hey there, one question:

when this happens (namely, I when have reply running via java -cp ... and this process spawns a nrepl server independently), what's the proper way to terminate the process?

Since ^C won't work, I have no other option than force-quitting with kill or such, which is bit of a hassle.

Update

As a workaround, one can use the clj repl which isn't as bad as vanilla clojure.main (but not as good as reply :) )

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