Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 70d1fc28801b
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2aabd988a4d6
Choose a head ref
  • 4 commits
  • 6 files changed
  • 2 contributors

Commits on Sep 1, 2016

  1. Copy the full SHA
    ffa2c63 View commit details

Commits on Sep 7, 2016

  1. Copy the full SHA
    08d64dc View commit details
  2. Also fix Interrupt class

    etehtsea committed Sep 7, 2016
    Copy the full SHA
    6b793be View commit details

Commits on Sep 15, 2016

  1. Merge pull request #4126 from etehtsea/gh-3954-signal-exception

    Implement SignalException class
    kares authored Sep 15, 2016
    Copy the full SHA
    2aabd98 View commit details
8 changes: 6 additions & 2 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -1610,8 +1610,10 @@ private void initExceptions() {
ioError = defineClassIfAllowed("IOError", standardError);
scriptError = defineClassIfAllowed("ScriptError", exceptionClass);
rangeError = defineClassIfAllowed("RangeError", standardError);
signalException = defineClassIfAllowed("SignalException", exceptionClass);

if (profile.allowClass("SignalException")) {
signalException = RubySignalException.createSignalExceptionClass(this, exceptionClass);
}
if (profile.allowClass("NameError")) {
nameError = RubyNameError.createNameErrorClass(this, standardError);
nameErrorMessage = RubyNameError.createNameErrorMessageClass(this, nameError);
@@ -1633,7 +1635,9 @@ private void initExceptions() {
}

fatal = defineClassIfAllowed("Fatal", exceptionClass);
interrupt = defineClassIfAllowed("Interrupt", signalException);
if (profile.allowClass("Interrupt")) {
interrupt = RubyInterrupt.createInterruptClass(this, signalException);
}
typeError = defineClassIfAllowed("TypeError", standardError);
argumentError = defineClassIfAllowed("ArgumentError", standardError);
if (profile.allowClass("UncaughtThrowError")) {
78 changes: 78 additions & 0 deletions core/src/main/java/org/jruby/RubyInterrupt.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/

package org.jruby;

import static jnr.constants.platform.Signal.SIGINT;

import org.jruby.anno.JRubyMethod;
import org.jruby.anno.JRubyClass;
import org.jruby.runtime.Block;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Arity;
import org.jruby.runtime.builtin.IRubyObject;
import static org.jruby.runtime.Visibility.PRIVATE;
import org.jruby.util.ArraySupport;

@JRubyClass(name="Interrupt", parent="SignalException")
public class RubyInterrupt extends RubySignalException {
private static final ObjectAllocator INTERRUPT_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyInterrupt(runtime, klass);
}
};

static RubyClass createInterruptClass(Ruby runtime, RubyClass signalExceptionClass) {
RubyClass interruptClass = runtime.defineClass("Interrupt", signalExceptionClass, INTERRUPT_ALLOCATOR);
interruptClass.defineAnnotatedMethods(RubyInterrupt.class);
return interruptClass;
}

protected RubyInterrupt(Ruby runtime, RubyClass exceptionClass) {
super(runtime, exceptionClass);
}

@JRubyMethod(optional = 1, visibility = PRIVATE)
@Override
public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block block) {
final Ruby runtime = context.runtime;

Arity.checkArgumentCount(runtime, args, 0, 1);

IRubyObject signo = runtime.newFixnum(SIGINT);

if (args.length > 0) {
args = ArraySupport.newCopy(signo, args);
} else {
args = new IRubyObject[]{signo, runtime.newString("Interrupt")};
}

super.initialize(args, block);
return this;
}
}
28 changes: 23 additions & 5 deletions core/src/main/java/org/jruby/RubySignal.java
Original file line number Diff line number Diff line change
@@ -74,9 +74,9 @@ public static Map<String, Integer> list() {
Map<String, Integer> signals = new HashMap<String, Integer>();

for (Signal s : Signal.values()) {
if (!s.description().startsWith("SIG"))
if (!s.description().startsWith(SIGNAME_PREFIX))
continue;
if (!RUBY_18_SIGNALS.contains(s.description().substring(3)))
if (!RUBY_18_SIGNALS.contains(signmWithoutPrefix(s.description())))
continue;

// replace CLD with CHLD value
@@ -88,7 +88,7 @@ public static Map<String, Integer> list() {
if (signo >= 20000)
continue;

signals.put(s.description().substring("SIG".length()), signo);
signals.put(signmWithoutPrefix(s.description()), signo);
}

return signals;
@@ -143,12 +143,28 @@ public static IRubyObject signame(ThreadContext context, final IRubyObject recv,
public static String signo2signm(long no) {
for (Signal s : Signal.values()) {
if (s.intValue() == no) {
return s.name().substring(3);
return signmWithoutPrefix(s.name());
}
}
return null;
}


// MRI: signm2signo
public static long signm2signo(String nm) {
for (Signal s : Signal.values()) {
if (signmWithoutPrefix(s.name()).equals(nm)) return s.longValue();
}
return 0;
}

public static String signmWithPrefix(String nm) {
return (nm.startsWith(SIGNAME_PREFIX)) ? nm : SIGNAME_PREFIX + nm;
}

public static String signmWithoutPrefix(String nm) {
return (nm.startsWith(SIGNAME_PREFIX)) ? nm.substring(SIGNAME_PREFIX.length()) : nm;
}

private static final Set<String> RUBY_18_SIGNALS;
static {
RUBY_18_SIGNALS = new HashSet<String>();
@@ -201,4 +217,6 @@ public static String signo2signm(long no) {
RUBY_18_SIGNALS.add(name);
}
}

private static final String SIGNAME_PREFIX = "SIG";
}// RubySignal
127 changes: 127 additions & 0 deletions core/src/main/java/org/jruby/RubySignalException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/

package org.jruby;

import static jnr.constants.platform.Signal.NSIG;

import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import static org.jruby.runtime.Visibility.PRIVATE;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.RubyBasicObject;
import org.jruby.RubySignal;
import org.jruby.util.TypeConverter;

@JRubyClass(name="SignalException", parent="Exception")
public class RubySignalException extends RubyException {
private static final ObjectAllocator SIGNAL_EXCEPTION_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubySignalException(runtime, klass);
}
};

protected RubySignalException(Ruby runtime, RubyClass exceptionClass) {
super(runtime, exceptionClass);
}

static RubyClass createSignalExceptionClass(Ruby runtime, RubyClass exceptionClass) {
RubyClass signalExceptionClass = runtime.defineClass("SignalException", exceptionClass, SIGNAL_EXCEPTION_ALLOCATOR);
signalExceptionClass.defineAnnotatedMethods(RubySignalException.class);

return signalExceptionClass;
}

@JRubyMethod(optional = 2, visibility = PRIVATE)
public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block block) {
final Ruby runtime = context.runtime;
int argnum = 1;
IRubyObject sig = context.nil;
long _signo;
int argc = args.length;

if (argc > 0) {
sig = TypeConverter.checkIntegerType(runtime, args[0], "to_int");

if (sig.isNil()) {
sig = args[0];
} else {
argnum = 2;
}
}

Arity.checkArgumentCount(runtime, args, 1, argnum);

if (argnum == 2) {
_signo = sig.convertToInteger().getLongValue();
if (_signo < 0 || _signo > NSIG.longValue()) {
throw runtime.newArgumentError("invalid signal number (" + _signo + ")");
}

if (argc > 1) {
sig = args[1];
} else {
sig = runtime.newString(RubySignal.signmWithPrefix(RubySignal.signo2signm(_signo)));
}
} else {
String signm = sig.toString();
_signo = RubySignal.signm2signo(RubySignal.signmWithoutPrefix(signm));

if (_signo == 0) {
throw runtime.newArgumentError("unsupported name " + sig);
}

sig = runtime.newString(RubySignal.signmWithPrefix(signm));
}

super.initialize(new IRubyObject[]{sig}, block);
this.signo = runtime.newFixnum(_signo);

return this;
}

@JRubyMethod
public IRubyObject signo(ThreadContext context) {
assert signo != null;

if (signo == RubyBasicObject.UNDEF) return context.nil;

return signo;
}

@JRubyMethod(name = {"message","signm"})
@Override
public IRubyObject message(ThreadContext context) {
return super.message(context);
}

private IRubyObject signo;
}
11 changes: 0 additions & 11 deletions spec/tags/ruby/core/exception/signal_exception_tags.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1 @@
fails:SignalException.new takes a signal number as the first argument
fails:SignalException.new raises an exception with an invalid signal number
fails:SignalException.new takes a signal name without SIG prefix as the first argument
fails:SignalException.new takes a signal name with SIG prefix as the first argument
fails:SignalException.new raises an exception with an invalid signal name
fails:SignalException.new takes a signal symbol without SIG prefix as the first argument
fails:SignalException.new takes a signal symbol with SIG prefix as the first argument
fails:SignalException.new raises an exception with an invalid signal name
fails:SignalException.new takes an optional message argument with a signal number
fails:SignalException.new raises an exception for an optional argument with a signal name
critical(crash):rescueing SignalException raises a SignalException when sent a signal
fails:rescueing SignalException raises a SignalException when sent a signal
3 changes: 1 addition & 2 deletions test/mri/excludes/TestSignal.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
exclude :test_exit_action, "kills test run"
exclude :test_hup_me, "kills test run"
exclude :test_kill_immediately_before_termination, "kills test run"
exclude :test_signal2, "SignalException needs to be its own class which provides a #signo accessor"
exclude :test_trap, "SignalException needs to be its own class which provides a #signo accessor"
exclude :test_signal_exception, "SignalException needs to be its own class which enforces args"
exclude :test_signame, "needs investigation - OutOfMemoryError"
exclude :test_trap_uncatchable_KILL, "uses SIGKILL which is already in use on the JVM"
exclude :test_trap_uncatchable_STOP, "uses SIGSTOP which is already in use on the JVM"
exclude :test_trap_puts, "fails due to use of INT. Works when the test uses SIGUSR2"
exclude :test_trap_system_default, "Test works, but JRuby's trap warning violates its stderr expectations"
exclude :test_trap_system_default, "Test works, but JRuby's trap warning violates its stderr expectations"