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

Commits on Nov 10, 2016

  1. [Truffle]

    eregon committed Nov 10, 2016
    Copy the full SHA
    493b9d4 View commit details
  2. [Truffle] Use System.getenv() and maintain the set of environment var…

    …iable names.
    
    * Avoids relying on environ which is not available on some platforms.
      Most notably, Solaris libc's environ points to null,
      the duplicate environ symbol in the process is used instead.
    * Drawback: an environment variable added by native code will not be seen
      by ENV#each and iterators, but can be accessed with ENV#[] nevertheless.
    * Clean up the code and group methods touching the internal state.
    * No need for putenv() or environ() anymore.
    eregon committed Nov 10, 2016
    Copy the full SHA
    394c972 View commit details
Original file line number Diff line number Diff line change
@@ -9,9 +9,14 @@
*/
package org.jruby.truffle.core;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;

import java.util.Set;

import org.jcodings.Encoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.ext.rbconfig.RbConfigLibrary;
import org.jruby.truffle.builtins.CoreClass;
@@ -24,6 +29,25 @@
@CoreClass("Truffle::System")
public abstract class TruffleSystemNodes {

@CoreMethod(names = "initial_environment_variables", onSingleton = true)
public abstract static class InitEnvVarsNode extends CoreMethodNode {

@TruffleBoundary
@Specialization
public DynamicObject envVars() {
final Set<String> variables = System.getenv().keySet();
final int size = variables.size();
final Encoding localeEncoding = getContext().getEncodingManager().getLocaleEncoding();
final Object[] store = new Object[size];
int i = 0;
for (String variable : variables) {
store[i++] = createString(StringOperations.encodeRope(variable, localeEncoding));
}
return createArray(store, size);
}

}

@CoreMethod(names = "host_cpu", onSingleton = true)
public abstract static class HostCPUNode extends CoreMethodNode {

Original file line number Diff line number Diff line change
@@ -91,22 +91,6 @@ public int dup(int descriptor) {

}

@CoreMethod(names = "environ", isModuleFunction = true, unsafe = {UnsafeGroup.MEMORY, UnsafeGroup.PROCESSES})
public abstract static class EnvironNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateObjectNode;

public EnvironNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNode.create();
}

@Specialization
public DynamicObject environ() {
return allocateObjectNode.allocate(coreLibrary().getRubiniusFFIPointerClass(), posix().environ());
}
}

@CoreMethod(names = "fchmod", isModuleFunction = true, required = 2, lowerFixnum = {1, 2}, unsafe = UnsafeGroup.IO)
public abstract static class FchmodNode extends CoreMethodArrayArgumentsNode {

@@ -266,17 +250,6 @@ public int mkfifo(DynamicObject path, int mode) {

}

@CoreMethod(names = "putenv", isModuleFunction = true, required = 1, unsafe = UnsafeGroup.PROCESSES)
public abstract static class PutenvNode extends CoreMethodArrayArgumentsNode {

@CompilerDirectives.TruffleBoundary
@Specialization(guards = "isRubyString(nameValuePair)")
public int putenv(DynamicObject nameValuePair) {
throw new UnsupportedOperationException("Not yet implemented in jnr-posix");
}

}

@CoreMethod(names = "readlink", isModuleFunction = true, required = 3, lowerFixnum = 3, unsafe = UnsafeGroup.IO)
public abstract static class ReadlinkNode extends CoreMethodArrayArgumentsNode {

Original file line number Diff line number Diff line change
@@ -87,11 +87,6 @@ public int fstat(int fd, FileStat stat) {
return posix.fstat(fd, stat);
}

@Override
public Pointer environ() {
return posix.environ();
}

@Override
public String getenv(String envName) {
return posix.getenv(envName);
Original file line number Diff line number Diff line change
@@ -35,7 +35,6 @@ public interface TrufflePosix {
int exec(String path, String[] argv, String[] envp);
int fork();
int fstat(int fd, FileStat stat);
Pointer environ();
String getenv(String envName);
int getegid();
int geteuid();
130 changes: 57 additions & 73 deletions truffle/src/main/ruby/core/env.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# Copyright (c) 2016 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

# Copyright (c) 2007-2015, Evan Phoenix and contributors
# All rights reserved.
#
@@ -32,21 +40,27 @@ module EnvironmentAccess
extend FFI::Library

attach_function :getenv, [:string], :string
attach_function :putenv, [:string], :int
attach_function :setenv, [:string, :string, :int], :int
attach_function :unsetenv, [:string], :int
attach_function :environ, 'ffi_environ', [], :pointer
end

class EnvironmentVariables
include Enumerable
include Rubinius::EnvironmentAccess

def initialize
vars = Truffle::System.initial_environment_variables
@variables = vars.map { |name| set_encoding(name) }
end

def size
@variables.size
end

def [](key)
value = getenv(StringValue(key))
if value
value = set_encoding value
value.freeze
value = set_encoding(value)
end
value
end
@@ -55,57 +69,42 @@ def []=(key, value)
key = StringValue(key)
if value.nil?
unsetenv(key)
@variables.delete(key)
else
if setenv(key, StringValue(value), 1) != 0
Errno.handle("setenv")
end
unless @variables.include?(key)
@variables << set_encoding(key.dup)
end
end
value
end

alias_method :store, :[]=

def each_key
return to_enum(:each_key) { size } unless block_given?

each { |k, v| yield k }
end

def each_value
return to_enum(:each_value) { size } unless block_given?

each { |k, v| yield v }
end

def each
return to_enum(:each) { size } unless block_given?

env = environ()
ptr_size = FFI.type_size FFI.find_type(:pointer)

offset = 0
cur = env + offset

until cur.read_pointer.null?
entry = cur.read_pointer.read_string
key, value = entry.split '=', 2
value.taint if value
key.taint if key

key = set_encoding key
value = set_encoding value

@variables.each do |name|
key = set_encoding(name)
value = self[name]
yield key, value

offset += ptr_size
cur = env + offset
end

self
end

alias_method :each_pair, :each

def each_key(&block)
@variables.each(&block)
end

def each_value
return to_enum(:each_value) { size } unless block_given?

each { |k, v| yield v }
end

def delete(key)
existing_value = self[key]
if existing_value
@@ -122,14 +121,23 @@ def delete_if(&block)
self
end

def shift
key = @variables.first
return nil unless key
value = delete key

key = set_encoding key
value = set_encoding value

return [key, value]
end

# More efficient than using the one from Enumerable
def include?(key)
!self[key].nil?
end

alias_method :has_key?, :include?
alias_method :key?, :include?

# More efficient than using the one from Enumerable
alias_method :member?, :include?

def fetch(key, absent=undefined)
@@ -165,9 +173,7 @@ def reject(&block)
def reject!
return to_enum(:reject!) { size } unless block_given?

# Avoid deleting from environ while iterating because the
# OS can handle that in a million different bad ways.

# Avoid deleting from the environment while iterating.
keys = []
each { |k, v| keys << k if yield(k, v) }
keys.each { |k| delete k }
@@ -176,9 +182,7 @@ def reject!
end

def clear
# Avoid deleting from environ while iterating because the
# OS can handle that in a million different bad ways.

# Avoid deleting from the environment while iterating.
keys = []
each { |k, v| keys << k }
keys.each { |k| delete k }
@@ -251,30 +255,6 @@ def select(&blk)
to_hash.select(&blk)
end

def shift
env = environ()

offset = 0
cur = env + offset

ptr = cur.read_pointer
return nil unless ptr

key, value = ptr.read_string.split "=", 2

return nil unless key

key.taint if key
value.taint if value

delete key

key = set_encoding key
value = set_encoding value

return [key, value]
end

def to_a
ary = []
each { |k, v| ary << [k, v] }
@@ -322,13 +302,17 @@ def rassoc(value)

def set_encoding(value)
return unless value.kind_of? String
if Encoding.default_internal && value.ascii_only?
value.encode Encoding.default_internal, Encoding.find("locale")
locale = Encoding.find("locale")
value = if Encoding.default_internal && value.ascii_only?
value.encode Encoding.default_internal, locale
elsif value.encoding != locale
value.dup.force_encoding(locale)
else
value.force_encoding Encoding.find("locale")
value
end
value.taint unless value.tainted?
value.freeze
end

private :set_encoding
end
end