Skip to content

Commit

Permalink
Merge 0e0338d into 5c57733
Browse files Browse the repository at this point in the history
  • Loading branch information
yaauie committed Jan 20, 2019
2 parents 5c57733 + 0e0338d commit cdcaefa
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 25 deletions.
16 changes: 7 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
os:
- linux
- osx

rvm:
- 1.9.3
- jruby-9.1.9.0
- rbx-3
- 2.0.0
- 2.1
- 2.2
- 2.3
- 2.4
- 2.5
- ruby-head

sudo: false

Expand All @@ -24,6 +15,9 @@ before_install:
- ruby -e "system('gem update --system') if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3')"
- gem install bundler --version '~> 1.17'

before_script:
- 'export JAVA_OPTS="${JAVA_OPTS_FOR_SPECS}"'

env:
global:
matrix:
Expand All @@ -36,6 +30,10 @@ matrix:
- rvm: jruby-9.1.9.0
- rvm: ruby-head
- env: "CHILDPROCESS_POSIX_SPAWN=true"
include:
- rvm: jruby-9.2.5.0
jvm: openjdk11
env: "JAVA_OPTS_FOR_SPECS='--add-opens java.base/java.io=org.jruby.dist --add-opens java.base/sun.nio.ch=org.jruby.dist'"
exclude:
# Travis does not provide 1.9.3 on OSX
- rvm: 1.9.3
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ ChildProcess.logger = logger
## Caveats

* With JRuby on Unix, modifying `ENV["PATH"]` before using childprocess could lead to 'Command not found' errors, since JRuby is unable to modify the environment used for PATH searches in `java.lang.ProcessBuilder`. This can be avoided by setting `ChildProcess.posix_spawn = true`.
* With JRuby on Java >= 9, the JVM may need to be configured to allow JRuby to access neccessary implementations; this can be done by adding `--add-opens java.base/java.io=org.jruby.dist` and `--add-opens java.base/sun.nio.ch=org.jruby.dist` to the `JAVA_OPTS` environment variable that is used by JRuby when launching the JVM.


# Implementation

Expand Down
57 changes: 41 additions & 16 deletions lib/childprocess/jruby/process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,49 @@ def wait
end
end

#
# Only supported in JRuby on a Unix operating system, thanks to limitations
# in Java's classes
#
# @return [Integer] the pid of the process after it has started
# @raise [NotImplementedError] when trying to access pid on non-Unix platform
#
def pid
if @process.getClass.getName != "java.lang.UNIXProcess"
raise NotImplementedError, "pid is only supported by JRuby child processes on Unix"
# Implementation of ChildProcess::JRuby::Process#pid depends heavily on
# what Java SDK is being used; here, we look it up once at load, then
# define the method once to avoid runtime overhead.
normalised_java_version_major = java.lang.System.get_property("java.version")
.slice(/^(1\.)?([0-9]+)/, 2)
.to_i
if normalised_java_version_major >= 9

# On modern Javas, we can simply delegate through to `Process#pid`,
# which was introduced in Java 9.
#
# @return [Integer] the pid of the process after it has started
# @raise [NotImplementedError] when trying to access pid on platform for
# which it is unsupported in Java
def pid
@process.pid
rescue java.lang.UnsupportedOperationException => e
raise NotImplementedError, "pid is not supported on this platform: #{e.message}"
end

else

# On Legacy Javas, fall back to reflection.
#
# Only supported in JRuby on a Unix operating system, thanks to limitations
# in Java's classes
#
# @return [Integer] the pid of the process after it has started
# @raise [NotImplementedError] when trying to access pid on non-Unix platform
#
def pid
if @process.getClass.getName != "java.lang.UNIXProcess"
raise NotImplementedError, "pid is only supported by JRuby child processes on Unix"
end

# About the best way we can do this is with a nasty reflection-based impl
# Thanks to Martijn Courteaux
# http://stackoverflow.com/questions/2950338/how-can-i-kill-a-linux-process-in-java-with-sigkill-process-destroy-does-sigter/2951193#2951193
field = @process.getClass.getDeclaredField("pid")
field.accessible = true
field.get(@process)
end

# About the best way we can do this is with a nasty reflection-based impl
# Thanks to Martijn Courteaux
# http://stackoverflow.com/questions/2950338/how-can-i-kill-a-linux-process-in-java-with-sigkill-process-destroy-does-sigter/2951193#2951193
field = @process.getClass.getDeclaredField("pid")
field.accessible = true
field.get(@process)
end

private
Expand Down

0 comments on commit cdcaefa

Please sign in to comment.