Class: Unicorn::App::Inetd::CatBody

Inherits:
Struct
  • Object
show all
Defined in:
lib/unicorn/app/inetd.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, cmd) ⇒ CatBody



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/unicorn/app/inetd.rb', line 12

def initialize(env, cmd)
  self.errors = env['rack.errors']
  in_rd, in_wr = IO.pipe
  self.err_rd, err_wr = IO.pipe
  self.out_rd, out_wr = IO.pipe

  cmd_pid = fork {
    inp, out, err = (0..2).map { |i| IO.new(i) }
    inp.reopen(in_rd)
    out.reopen(out_wr)
    err.reopen(err_wr)
    [ in_rd, in_wr, err_rd, err_wr, out_rd, out_wr ].each { |i| i.close }
    exec(*cmd)
  }
  [ in_rd, err_wr, out_wr ].each { |io| io.close }
  [ in_wr, err_rd, out_rd ].each { |io| io.binmode }
  in_wr.sync = true

  # Unfortunately, input here must be processed inside a seperate
  # thread/process using blocking I/O since env['rack.input'] is not
  # IO.select-able and attempting to make it so would trip Rack::Lint
  inp_pid = fork {
    input = env['rack.input']
    [ err_rd, out_rd ].each { |io| io.close }

    # this is dependent on input.read having readpartial semantics:
    buf = input.read(16384)
    begin
      in_wr.write(buf)
    end while input.read(16384, buf)
  }
  in_wr.close
  self.pid_map = {
    inp_pid => 'input streamer',
    cmd_pid => cmd.inspect,
  }
end

Instance Attribute Details

#err_rdObject

Returns the value of attribute err_rd



11
12
13
# File 'lib/unicorn/app/inetd.rb', line 11

def err_rd
  @err_rd
end

#errorsObject

Returns the value of attribute errors



11
12
13
# File 'lib/unicorn/app/inetd.rb', line 11

def errors
  @errors
end

#out_rdObject

Returns the value of attribute out_rd



11
12
13
# File 'lib/unicorn/app/inetd.rb', line 11

def out_rd
  @out_rd
end

#pid_mapObject

Returns the value of attribute pid_map



11
12
13
# File 'lib/unicorn/app/inetd.rb', line 11

def pid_map
  @pid_map
end

Instance Method Details

#closeObject



79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/unicorn/app/inetd.rb', line 79

def close
  pid_map.each { |pid, str|
    begin
      pid, status = Process.waitpid2(pid)
      status.success? or
        errors.write("#{str}: #{status.inspect} (PID:#{pid})\n")
    rescue Errno::ECHILD
      errors.write("Failed to reap #{str} (PID:#{pid})\n")
    end
  }
  out_rd.close
  err_rd.close
end

#each(&block) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/unicorn/app/inetd.rb', line 50

def each(&block)
  begin
    rd, = IO.select([err_rd, out_rd])
    rd && rd.first or next

    if rd.include?(err_rd)
      begin
        errors.write(err_rd.read_nonblock(16384))
      rescue Errno::EINTR
      rescue Errno::EAGAIN
        break
      end while true
    end

    rd.include?(out_rd) or next

    begin
      yield out_rd.read_nonblock(16384)
    rescue Errno::EINTR
    rescue Errno::EAGAIN
      break
    end while true
  rescue EOFError,Errno::EPIPE,Errno::EBADF,Errno::EINVAL
    break
  end while true

  self
end