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: bc4bacad52fc
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9c794dc65727
Choose a head ref
  • 3 commits
  • 10 files changed
  • 1 contributor

Commits on Feb 5, 2015

  1. Copy the full SHA
    317a27e View commit details
  2. [Truffle] Full Signal.trap support.

    * A mix of Rubinius, JRuby and self-made.
    eregon committed Feb 5, 2015
    2
    Copy the full SHA
    85856b5 View commit details
  3. Copy the full SHA
    9c794dc View commit details
33 changes: 22 additions & 11 deletions core/src/main/java/org/jruby/RubySignal.java
Original file line number Diff line number Diff line change
@@ -28,11 +28,11 @@
package org.jruby;

import jnr.constants.platform.Signal;

import org.jruby.anno.JRubyMethod;
import org.jruby.anno.JRubyModule;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

import org.jruby.util.SignalFacade;
import org.jruby.util.NoFunctionalitySignalFacade;

@@ -58,23 +58,34 @@ public static void createSignal(Ruby runtime) {
//registerThreadDumpSignalHandler(runtime);
}

@JRubyMethod(meta = true)
public static IRubyObject list(ThreadContext context, IRubyObject recv) {
Ruby runtime = recv.getRuntime();
RubyHash names = RubyHash.newHash(runtime);
public static Map<String, Integer> list() {
Map<String, Integer> signals = new HashMap<String, Integer>();

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

// replace CLD with CHLD value
long longValue = s.longValue();
if (s == Signal.SIGCLD) longValue = Signal.SIGCHLD.longValue();
int longValue = s.intValue();
if (s == Signal.SIGCLD)
longValue = Signal.SIGCHLD.intValue();

// omit unsupported signals
if (longValue >= 20000) continue;
if (longValue >= 20000)
continue;

names.op_aset(context, runtime.newString(s.description().substring("SIG".length())), runtime.newFixnum(longValue));
signals.put(s.description().substring("SIG".length()), longValue);
}

return signals;
}

@JRubyMethod(meta = true)
public static IRubyObject list(ThreadContext context, IRubyObject recv) {
Ruby runtime = recv.getRuntime();
RubyHash names = RubyHash.newHash(runtime, RubySignal.list(), runtime.getNil());
names.op_aset(context, runtime.newString("EXIT"), runtime.newFixnum(0));
return names;
}
16 changes: 0 additions & 16 deletions spec/truffle/tags/core/signal/trap_tags.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,2 @@
fails:Signal.trap returns the previous handler
fails:Signal.trap accepts a block in place of a proc/command argument
fails:Signal.trap ignores the signal when passed nil
fails:Signal.trap accepts 'DEFAULT' as a symbol in place of a proc
fails:Signal.trap accepts 'SIG_DFL' as a symbol in place of a proc
fails:Signal.trap accepts 'SIG_IGN' as a symbol in place of a proc
fails:Signal.trap accepts 'IGNORE' as a symbol in place of a proc
fails:Signal.trap accepts long names as Strings
fails:Signal.trap acceps short names as Strings
fails:Signal.trap accepts long names as Symbols
fails:Signal.trap accepts short names as Symbols
fails:Signal.trap accepts 'SIG_DFL' in place of a proc
fails:Signal.trap accepts 'DEFAULT' in place of a proc
fails:Signal.trap accepts 'SIG_IGN' in place of a proc
fails:Signal.trap accepts 'IGNORE' in place of a proc
fails:Signal.trap the special EXIT signal code accepts the EXIT code
fails:Signal.trap the special EXIT signal code runs the proc before at_exit handlers
fails:Signal.trap the special EXIT signal code can unset the handler
Original file line number Diff line number Diff line change
@@ -475,12 +475,13 @@ public Object deletePackedArray(VirtualFrame frame, RubyHash hash, Object key) {
final Object[] store = (Object[]) hash.getStore();
final int size = hash.getSize();

for (int n = 0; n < HashOperations.SMALL_HASH_SIZE * 2; n += 2) {
if (n < size && eqlNode.callBoolean(frame, store[n], "eql?", null, key)) {
final Object value = store[n + 1];
for (int n = 0; n < HashOperations.SMALL_HASH_SIZE; n++) {
if (n < size && eqlNode.callBoolean(frame, store[n * 2], "eql?", null, key)) {
final Object value = store[n * 2 + 1];

// Move the later values down
System.arraycopy(store, n + 2, store, n, HashOperations.SMALL_HASH_SIZE * 2 - n - 2);
int k = n * 2; // position of the key
System.arraycopy(store, k + 2, store, k, (size - n - 1) * 2);

hash.setSize(size - 1);

@@ -785,8 +786,8 @@ public boolean keyPackedArray(VirtualFrame frame, RubyHash hash, Object key) {
final int size = hash.getSize();
final Object[] store = (Object[]) hash.getStore();

for (int n = 0; n < store.length; n += 2) {
if (n < size && eqlNode.callBoolean(frame, store[n], "eql?", null, key)) {
for (int n = 0; n < HashOperations.SMALL_HASH_SIZE; n++) {
if (n < size && eqlNode.callBoolean(frame, store[n * 2], "eql?", null, key)) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -11,11 +11,45 @@

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubySymbol;
import org.jruby.truffle.runtime.signal.SignalOperations;

import sun.misc.Signal;

@CoreClass(name = "Process")
public abstract class ProcessNodes {

@CoreMethod(names = "kill", isModuleFunction = true, required = 2)
public abstract static class KillNode extends CoreMethodNode {

public KillNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public KillNode(KillNode prev) {
super(prev);
}

@Specialization
public int kill(RubySymbol signalName, int pid) {
notDesignedForCompilation();

int self = getContext().getRuntime().getPosix().getpid();

if (self == pid) {
Signal signal = new Signal(signalName.toString());

SignalOperations.raise(signal);
return 1;
} else {
throw new UnsupportedOperationException();
}
}

}

@CoreMethod(names = "pid", isModuleFunction = true)
public abstract static class PidNode extends CoreMethodNode {

75 changes: 15 additions & 60 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/SignalNodes.java
Original file line number Diff line number Diff line change
@@ -9,84 +9,39 @@
*/
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;
import java.util.Map;

import org.jruby.common.IRubyWarnings;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
import org.jruby.truffle.runtime.core.RubyNilClass;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.core.RubySymbol;
import org.jruby.truffle.runtime.signal.ProcSignalHandler;
import org.jruby.truffle.runtime.signal.SignalOperations;

import sun.misc.Signal;
import sun.misc.SignalHandler;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

@CoreClass(name = "Signal")
public abstract class SignalNodes {

@CoreMethod(names = "trap", isModuleFunction = true, needsBlock = true, required = 1, optional = 1)
public abstract static class SignalNode extends CoreMethodNode {
@CoreMethod(names = "setup_signal_list", onSingleton = true, needsBlock = true, visibility = Visibility.PRIVATE)
public abstract static class SetupSignalListNode extends YieldingCoreMethodNode {

public SignalNode(RubyContext context, SourceSection sourceSection) {
public SetupSignalListNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public SignalNode(SignalNode prev) {
public SetupSignalListNode(SetupSignalListNode prev) {
super(prev);
}

@Specialization
public Object trap(RubySymbol signalName, UndefinedPlaceholder command, RubyProc block) {
return trap(signalName.toString(), block);
}

@Specialization
public Object trap(RubyString signalName, UndefinedPlaceholder command, RubyProc block) {
return trap(signalName.toString(), block);
}

@Specialization
public Object trap(RubySymbol signalName, RubyProc proc, UndefinedPlaceholder block) {
return trap(signalName.toString(), proc);
}

@Specialization
public Object trap(RubyString signalName, RubyProc proc, UndefinedPlaceholder block) {
return trap(signalName.toString(), proc);
}

@SuppressWarnings("restriction")
private Object trap(String signalName, RubyProc block) {
notDesignedForCompilation();

final Signal signal = new Signal(signalName);

final SignalHandler newHandler = new ProcSignalHandler(getContext(), block);
final SignalHandler oldHandler = Signal.handle(signal, newHandler);

if (oldHandler instanceof ProcSignalHandler) {
return ((ProcSignalHandler) oldHandler).getProc();
public RubyNilClass setupSignalList(VirtualFrame frame, RubyProc block) {
for (Map.Entry<String, Integer> signal : SignalOperations.SIGNALS_LIST.entrySet()) {
RubyString signalName = getContext().makeString(signal.getKey());
yield(frame, block, signalName, signal.getValue());
}

return getContext().getCoreLibrary().getNilObject();
}

@Specialization
public Object trap(RubySymbol signalName, RubyString command, UndefinedPlaceholder block) {
return trap(signalName.toString(), command, block);
}

@Specialization
public Object trap(RubyString signalName, RubyString command, UndefinedPlaceholder block) {
return trap(signalName.toString(), command, block);
}

private Object trap(String signalName, RubyString command, UndefinedPlaceholder block) {
notDesignedForCompilation();
getContext().getRuntime().getWarnings().warn(IRubyWarnings.ID.TRUFFLE, Truffle.getRuntime().getCallerFrame().getCallNode().getEncapsulatingSourceSection().getSource().getName(), Truffle.getRuntime().getCallerFrame().getCallNode().getEncapsulatingSourceSection().getStartLine(), "Signal#trap with a string command not implemented yet");
return getContext().getCoreLibrary().getNilObject();
}

Original file line number Diff line number Diff line change
@@ -20,6 +20,10 @@
import org.jruby.truffle.nodes.objects.ClassNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.signal.ProcSignalHandler;
import org.jruby.truffle.runtime.signal.SignalOperations;

import sun.misc.Signal;

/**
* Rubinius primitives associated with the VM.
@@ -214,4 +218,46 @@ public Object vmSingletonClassObject(Object object) {

}

@SuppressWarnings("restriction")
@RubiniusPrimitive(name = "vm_watch_signal", needsSelf = false)
public static abstract class VMWatchSignalPrimitiveNode extends RubiniusPrimitiveNode {

public VMWatchSignalPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public VMWatchSignalPrimitiveNode(VMWatchSignalPrimitiveNode prev) {
super(prev);
}

@Specialization
public boolean watchSignal(RubyString signalName, RubyString action) {
if (!action.toString().equals("DEFAULT")) {
throw new UnsupportedOperationException();
}

Signal signal = new Signal(signalName.toString());

SignalOperations.watchDefaultForSignal(signal);
return true;
}

@Specialization
public boolean watchSignal(RubyString signalName, RubyNilClass ignore) {
Signal signal = new Signal(signalName.toString());

SignalOperations.watchSignal(signal, SignalOperations.IGNORE_HANDLER);
return true;
}

@Specialization
public boolean watchSignal(RubyString signalName, RubyProc proc) {
Signal signal = new Signal(signalName.toString());

SignalOperations.watchSignal(signal, new ProcSignalHandler(getContext(), proc));
return true;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.runtime.signal;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.jruby.RubySignal;

import sun.misc.Signal;
import sun.misc.SignalHandler;

@SuppressWarnings("restriction")
public class SignalOperations {

private static final ConcurrentMap<Signal, SignalHandler> ORIGINAL_HANDLERS = new ConcurrentHashMap<Signal, SignalHandler>();

public static final Map<String, Integer> SIGNALS_LIST = RubySignal.list();

public static final SignalHandler IGNORE_HANDLER = new SignalHandler() {
@Override
public void handle(Signal arg0) {
// Just ignore the signal.
}
};

public static void watchSignal(Signal signal, SignalHandler newHandler) {
SignalHandler oldHandler = Signal.handle(signal, newHandler);
ORIGINAL_HANDLERS.putIfAbsent(signal, oldHandler);
}

public static void watchDefaultForSignal(Signal signal) {
SignalHandler defaultHandler = ORIGINAL_HANDLERS.get(signal);
if (defaultHandler != null) {
Signal.handle(signal, defaultHandler);
}
}

public static void raise(Signal signal) {
Signal.raise(signal);
}

}
2 changes: 2 additions & 0 deletions truffle/src/main/ruby/jruby/truffle/core.rb
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@
require_relative 'core/rubinius/kernel/bootstrap/kernel'
require_relative 'core/rubinius/kernel/bootstrap/nil'
require_relative 'core/rubinius/kernel/bootstrap/regexp'
require_relative 'core/rubinius/kernel/bootstrap/rubinius'
require_relative 'core/rubinius/kernel/bootstrap/string'
require_relative 'core/rubinius/kernel/bootstrap/symbol'
require_relative 'core/rubinius/kernel/bootstrap/time'
@@ -53,6 +54,7 @@
require_relative 'core/rubinius/kernel/common/string'
require_relative 'core/rubinius/kernel/common/struct'
require_relative 'core/rubinius/kernel/common/regexp'
require_relative 'core/rubinius/kernel/common/signal'
require_relative 'core/rubinius/kernel/common/mutex'
require_relative 'core/rubinius/kernel/common/time'
require_relative 'core/rubinius/kernel/common/true'
Loading