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

Commits on Jun 17, 2016

  1. Copy the full SHA
    3cfd8cc View commit details
  2. [Truffle] Support redirecting FDs in #spawn.

    * Add back removed code.
    * Do not warn if no graal in ruby/spec child processes.
    eregon committed Jun 17, 2016
    Copy the full SHA
    d0f7a03 View commit details
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/process/spawn_tags.txt
Original file line number Diff line number Diff line change
@@ -25,11 +25,7 @@ fails:Process.spawn raises a TypeError if given a symbol as :pgroup option
fails:Process.spawn uses the current working directory as its working directory
fails:Process.spawn uses the current umask by default
fails:Process.spawn sets the umask if given the :umask option
fails:Process.spawn redirects STDOUT to the given file descriptior if out: Fixnum
fails:Process.spawn redirects STDOUT to the given file if out: IO
fails:Process.spawn redirects STDOUT to the given file if out: String
fails:Process.spawn redirects STDERR to the given file descriptior if err: Fixnum
fails:Process.spawn redirects STDERR to the given file descriptor if err: IO
fails:Process.spawn redirects STDERR to the given file if err: String
fails:Process.spawn redirects both STDERR and STDOUT to the given file descriptior
fails:Process.spawn redirects both STDERR and STDOUT to the given IO
2 changes: 1 addition & 1 deletion spec/truffle/truffle.mspec
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ class MSpecScript
set :target, File.expand_path("../../../bin/jruby#{windows? ? '.bat' : ''}", __FILE__)

if ARGV[-2..-1] != %w[-t ruby] # No flags for MRI
set :flags, %w[-X+T -J-ea -J-esa -J-Xmx2G]
set :flags, %w[-X+T -J-ea -J-esa -J-Xmx2G -Xtruffle.graal.warn_unless=false]
end

set :capi, [
Original file line number Diff line number Diff line change
@@ -18,31 +18,39 @@
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.core.array.ArrayOperations;
import org.jruby.truffle.core.hash.HashOperations;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.platform.UnsafeGroup;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map.Entry;

@CoreClass("Truffle::Process")
public abstract class TruffleProcessNodes {

@CoreMethod(names = "spawn", onSingleton = true, required = 3, unsafe = UnsafeGroup.PROCESSES)
@CoreMethod(names = "spawn", onSingleton = true, required = 4, unsafe = UnsafeGroup.PROCESSES)
public abstract static class SpawnNode extends CoreMethodArrayArgumentsNode {

@Specialization(guards = {
"isRubyString(command)",
"isRubyArray(arguments)",
"isRubyArray(environmentVariables)" })
"isRubyArray(environmentVariables)",
"isRubyHash(options)" })
public int spawn(DynamicObject command,
DynamicObject arguments,
DynamicObject environmentVariables) {
DynamicObject environmentVariables,
DynamicObject options) {

Collection<SpawnFileAction> fileActions = parseOptions(options);

final long longPid = call(
StringOperations.getString(getContext(), command),
toStringArray(arguments),
toStringArray(environmentVariables));
toStringArray(environmentVariables),
fileActions);
assert longPid <= Integer.MAX_VALUE;
// VMWaitPidPrimitiveNode accepts only int
final int pid = (int) longPid;
@@ -69,11 +77,44 @@ private String[] toStringArray(DynamicObject rubyStrings) {
}

@TruffleBoundary
private long call(String command, String[] arguments, String[] environmentVariables) {
private Collection<SpawnFileAction> parseOptions(DynamicObject options) {
if (Layouts.HASH.getSize(options) == 0) {
return Collections.emptyList();
}

Collection<SpawnFileAction> actions = new ArrayList<>();
for (Entry<Object, Object> keyValue : HashOperations.iterableKeyValues(options)) {
final Object key = keyValue.getKey();
final Object value = keyValue.getValue();

if (Layouts.SYMBOL.isSymbol(key)) {
if (key == getSymbol("redirect_fd")) {
assert Layouts.ARRAY.isArray(value);
final DynamicObject array = (DynamicObject) value;
final int size = Layouts.ARRAY.getSize(array);
assert size % 2 == 0;
final Object[] store = ArrayOperations.toObjectArray(array);
for (int i = 0; i < size; i += 2) {
int from = (int) store[i];
int to = (int) store[i + 1];
actions.add(SpawnFileAction.dup(to, from));
actions.add(SpawnFileAction.close(to));
}
continue;
}
}
throw new UnsupportedOperationException("Unsupported spawn option: " + key + " => " + value);
}

return actions;
}

@TruffleBoundary
private long call(String command, String[] arguments, String[] environmentVariables, Collection<SpawnFileAction> fileActions) {
// TODO (pitr 04-Sep-2015): only simple implementation, does not support file actions or other options
return getContext().getNativePlatform().getPosix().posix_spawnp(
command,
Collections.<SpawnFileAction>emptyList(),
fileActions,
Arrays.asList(arguments),
Arrays.asList(environmentVariables));

2 changes: 2 additions & 0 deletions truffle/src/main/ruby/core/io.rb
Original file line number Diff line number Diff line change
@@ -1914,6 +1914,8 @@ def pid
@pid
end

attr_writer :pid

def pipe=(v)
@pipe = !!v
end
21 changes: 18 additions & 3 deletions truffle/src/main/ruby/core/process_mirror.rb
Original file line number Diff line number Diff line change
@@ -230,6 +230,19 @@ def default_mode(target)
end
end

def convert_file_mode(obj)
case obj
when ::Fixnum
obj
when ::String
OFLAGS[obj]
when nil
OFLAGS["r"]
else
Rubinius::Type.coerce_to obj, Integer, :to_int
end
end

# Mapping of string open modes to integer oflag versions.
OFLAGS = {
"r" => ::File::RDONLY,
@@ -242,16 +255,18 @@ def default_mode(target)

def spawn(options, command, arguments)
options ||= {}
env = options[:unsetenv_others] ? {} : ENV.to_hash
env.merge! Hash[options[:env]] if options[:env]
env = options.delete(:unsetenv_others) ? {} : ENV.to_hash
if add_to_env = options.delete(:env)
env.merge! Hash[add_to_env]
end

env_array = env.map { |k, v| "#{k}=#{v}" }

if arguments.empty?
command, arguments = 'bash', ['bash', '-c', command]
end

Truffle::Process.spawn command, arguments, env_array
Truffle::Process.spawn command, arguments, env_array, options
end

def exec(command, args)