Last active
December 20, 2015 00:19
-
-
Save zipizap/6040947 to your computer and use it in GitHub Desktop.
Pass a file-descriptor between 2 processes, using UnixSockets - (MRI vs Jruby limitations)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'socket' | |
require 'spoon' | |
# I made this code to experiment with 2 things: | |
# 1) Use the 'spoon' gem and Spoon.spawnp as a poor-man-substitute of a normal fork | |
# 2) pass a file-descriptor over unix-sockets, from a parent process to a child process | |
# | |
# Jruby cannot .fork() as MRI Ruby... it seems the alternative is 'spoon' gem and its | |
# spawn/spawnp methods. | |
# Fork is not the same as spawning: basically fork will copy to a child process all | |
# file-descriptors and continue to execute ruby code. Spawn is fork+exec = start executing | |
# another external program (not internal code) with file-descriptors independence. | |
# To make a poor-man-fork with spawn, the idea is to spawn the same program in a child-process, | |
# but that child-process does not have access to parent's file descriptors. To pass the | |
# file-descriptor from parent-process to child-process, a unix socket is created by the parent, | |
# and given as argument to the child-process when spawning it. The child-process will then read | |
# the unix-socket and receive from it the file-descriptor of the parent (unix sockets CAN do that, | |
# google "unix socket pass file-descriptor"). | |
# | |
# After joining these pieces, I've made this code and saw that the unix-socket communication was | |
# good, that 'spoon' was working as expected and that the file-descriptor is passed correctly | |
# with UNIXSocket#send_io/recv_i. All works in MRI Ruby, but in Jruby unfortunately, neither | |
# fork() (because of jruby limitation) nor file-descriptor-passing-in-unix-sockets works | |
# (no errors, ?maybe a bug?). | |
# | |
# So, dear reader, I hope this helps you for whatever reason, and leave it published in the internets | |
# | |
# zipizap 19/07/2013 | |
# | |
#. | |
# | |
# | |
if ARGV[0].nil? | |
#parent: "ruby this-file.rb" | |
puts "p> Im parent" | |
fd = File.open("/tmp/a.tmp",'w') | |
fd.puts "Im parent" | |
#create unix socket | |
uskt_file = "/tmp/unix_socket" | |
%x(rm -f #{uskt_file} &>/dev/null) | |
uskt_server = UNIXServer.new(uskt_file) | |
#spawn child process | |
puts "p> pre spawning" | |
# child_pid = Spoon.spawnp(*%W(java -jar deployment/jruby.jar #{$0} #{uskt_file})) | |
child_pid = Spoon.spawnp(*%W(ruby #{$0} #{uskt_file})) | |
Process.detach(child_pid) | |
puts "p> pos spawning" | |
#accept unix socket connections | |
puts "p> pre accept" | |
uskt_server_with_client = uskt_server.accept | |
puts "p> pos accept" | |
#send fd into unix socket | |
puts "p> going to send fd=#{fd.inspect}" | |
uskt_server_with_client.send_io fd | |
#close unix socket | |
uskt_server_with_client.close | |
fd.close | |
#child will rm unix socket | |
#parent process exit | |
puts "p> bye" | |
exit 0 | |
elsif File.socket?(ARGV[0]||"") | |
#child: "ruby this-file.rb /tmp/unix_socket" | |
puts "c> Im child" | |
uskt_file = ARGV[0] | |
#open unix socket of arg[0] | |
puts "c> going to open unix socket" | |
uskt = UNIXSocket.open(uskt_file) | |
#read fd from unix socket | |
puts "c> pre read " | |
fd = uskt.recv_io | |
puts "c> pos read fd=#{fd.inspect}" | |
# #write into fd | |
fd.puts "Im child" | |
#close unix socket | |
uskt.close | |
fd.close | |
#rm unix socket file | |
%x(rm -f #{uskt_file} &>/dev/null) | |
#child process exit | |
puts "c> bye" | |
exit 0 | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment