Skip to content

Commit 7b18925

Browse files
committed
[GR-19220] Fix use of vm_watch_signal as it now passes signo (#2293)
PullRequest: truffleruby/2490
2 parents 445b72a + aadb128 commit 7b18925

File tree

6 files changed

+51
-13
lines changed

6 files changed

+51
-13
lines changed

spec/ruby/core/exception/interrupt_spec.rb

+17-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,23 @@
2929
sleep
3030
rescue Interrupt => e
3131
e.signo.should == Signal.list["INT"]
32-
e.signm.should == ""
32+
["", "Interrupt"].should.include?(e.message)
3333
end
3434
end
3535
end
36+
37+
describe "Interrupt" do
38+
# This spec is basically the same as above,
39+
# but it does not rely on Signal.trap(:INT, :SIG_DFL) which can be tricky
40+
it "is raised on the main Thread by the default SIGINT handler" do
41+
out = ruby_exe(<<-'RUBY', args: "2>&1")
42+
begin
43+
Process.kill :INT, Process.pid
44+
sleep
45+
rescue Interrupt => e
46+
puts "Interrupt: #{e.signo}"
47+
end
48+
RUBY
49+
out.should == "Interrupt: #{Signal.list["INT"]}\n"
50+
end
51+
end
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
fails:rescuing Interrupt raises an Interrupt when sent a signal SIGINT
1+
slow:Interrupt is raised on the main Thread by the default SIGINT handler

src/main/java/org/truffleruby/core/VMPrimitiveNodes.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ public static abstract class VMWatchSignalNode extends PrimitiveArrayArgumentsNo
228228

229229
@TruffleBoundary
230230
@Specialization(guards = { "libSignalString.isRubyString(signalString)", "libAction.isRubyString(action)" })
231-
protected boolean restoreDefault(Object signalString, Object action,
231+
protected boolean watchSignalString(Object signalString, boolean isRubyDefaultHandler, Object action,
232232
@CachedLibrary(limit = "2") RubyStringLibrary libSignalString,
233233
@CachedLibrary(limit = "2") RubyStringLibrary libAction) {
234234
final String actionString = libAction.getJavaString(action);
@@ -248,7 +248,7 @@ protected boolean restoreDefault(Object signalString, Object action,
248248

249249
@TruffleBoundary
250250
@Specialization(guards = "libSignalString.isRubyString(signalString)")
251-
protected boolean watchSignalProc(Object signalString, RubyProc action,
251+
protected boolean watchSignalProc(Object signalString, boolean isRubyDefaultHandler, RubyProc action,
252252
@CachedLibrary(limit = "2") RubyStringLibrary libSignalString) {
253253
final RubyContext context = getContext();
254254

@@ -265,7 +265,7 @@ protected boolean watchSignalProc(Object signalString, RubyProc action,
265265
"Handling of signal " + signal,
266266
SafepointPredicate.currentFiberOfThread(context, rootThread),
267267
(rubyThread, currentNode) -> ProcOperations.rootCall(action, signal.getNumber()));
268-
});
268+
}, isRubyDefaultHandler);
269269
}
270270

271271
@TruffleBoundary
@@ -277,7 +277,7 @@ private boolean restoreDefaultHandler(String signalName) {
277277
}
278278

279279
try {
280-
return Signals.restoreDefaultHandler(signalName);
280+
return Signals.restoreRubyDefaultHandler(signalName);
281281
} catch (IllegalArgumentException e) {
282282
throw new RaiseException(getContext(), coreExceptions().argumentError(e.getMessage(), this));
283283
}
@@ -316,15 +316,15 @@ private boolean registerIgnoreHandler(String signalName) {
316316
}
317317

318318
@TruffleBoundary
319-
private boolean registerHandler(String signalName, SignalHandler newHandler) {
319+
private boolean registerHandler(String signalName, SignalHandler newHandler, boolean isRubyDefaultHandler) {
320320
if (getContext().getOptions().EMBEDDED) {
321321
RubyLanguage.LOGGER.warning(
322322
"trapping signal " + signalName +
323323
" in embedded mode may interfere with other embedded contexts or the host system");
324324
}
325325

326326
try {
327-
Signals.registerHandler(newHandler, signalName);
327+
Signals.registerHandler(newHandler, signalName, isRubyDefaultHandler);
328328
} catch (IllegalArgumentException e) {
329329
throw new RaiseException(getContext(), coreExceptions().argumentError(e.getMessage(), this));
330330
}

src/main/java/org/truffleruby/platform/Signals.java

+23-1
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,18 @@ public class Signals {
2424
};
2525

2626
// Use String and not Signal as key to work around SVM not allowing new Signal("PROF")
27+
/** Default SignalHandlers for the JVM */
2728
private static final ConcurrentMap<String, SignalHandler> DEFAULT_HANDLERS = new ConcurrentHashMap<>();
29+
/** Default signal handlers for Ruby, only SIGINT and SIGALRM, see {@code core/main.rb} */
30+
private static final ConcurrentMap<String, SignalHandler> RUBY_DEFAULT_HANDLERS = new ConcurrentHashMap<>();
2831

29-
public static void registerHandler(SignalHandler newHandler, String signalName) {
32+
public static void registerHandler(SignalHandler newHandler, String signalName, boolean isRubyDefaultHandler) {
3033
final Signal signal = new Signal(signalName);
3134
final SignalHandler oldHandler = Signal.handle(signal, newHandler);
3235
DEFAULT_HANDLERS.putIfAbsent(signalName, oldHandler);
36+
if (isRubyDefaultHandler) {
37+
RUBY_DEFAULT_HANDLERS.putIfAbsent(signalName, newHandler);
38+
}
3339
}
3440

3541
public static void registerIgnoreHandler(String signalName) {
@@ -50,6 +56,22 @@ public static boolean restoreDefaultHandler(String signalName) {
5056
}
5157
}
5258

59+
public static boolean restoreRubyDefaultHandler(String signalName) {
60+
SignalHandler defaultHandler = RUBY_DEFAULT_HANDLERS.get(signalName);
61+
if (defaultHandler == null) {
62+
defaultHandler = DEFAULT_HANDLERS.get(signalName);
63+
}
64+
65+
if (defaultHandler == null) {
66+
// it is already the default signal
67+
return false;
68+
} else {
69+
final Signal signal = new Signal(signalName);
70+
Signal.handle(signal, defaultHandler);
71+
return true;
72+
}
73+
}
74+
5375
public static void restoreSystemHandler(String signalName) {
5476
final Signal signal = new Signal(signalName);
5577
Signal.handle(signal, SignalHandler.SIG_DFL);

src/main/ruby/truffleruby/core/main.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ def to_s
7070
}
7171

7272
Truffle::Boot.delay do
73-
# Use vm_watch_signal directly as those should be the 'DEFAULT' handlers
73+
# Use vm_watch_signal directly as those should be the default Ruby handlers
7474

7575
if Truffle::Boot.get_option('platform-handle-interrupt')
76-
Primitive.vm_watch_signal 'INT', -> do
76+
Primitive.vm_watch_signal 'INT', true, -> _signo do
7777
if Truffle::Boot.get_option('backtraces-on-interrupt')
7878
puts 'Interrupting...'
7979
show_backtraces.call
@@ -84,7 +84,7 @@ def to_s
8484
end
8585

8686
if Truffle::Boot.get_option('backtraces-sigalrm')
87-
Primitive.vm_watch_signal 'ALRM', -> do
87+
Primitive.vm_watch_signal 'ALRM', true, -> _signo do
8888
show_backtraces.call
8989
end
9090
end

src/main/ruby/truffleruby/core/signal.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def self.trap(signal, handler=nil, &block)
117117
end
118118

119119
if number != Names['EXIT']
120-
ret = Primitive.vm_watch_signal(signame, handler || 'IGNORE')
120+
ret = Primitive.vm_watch_signal(signame, false, handler || 'IGNORE')
121121
if handler == 'DEFAULT' && !ret
122122
return +'SYSTEM_DEFAULT'
123123
end

0 commit comments

Comments
 (0)