Class: NewRelic::Agent::PipeChannelManager::Pipe

Inherits:
Object
  • Object
show all
Defined in:
lib/new_relic/agent/pipe_channel_manager.rb

Overview

Expected initial sequence of events for Pipe usage:

  1. Pipe is created in parent process (read and write ends open)

  2. Parent process forks

  3. An after_fork hook is invoked in the child

  4. From after_fork hook, child closes read end of pipe, and writes a ready marker on the pipe (after_fork_in_child).

  5. The parent receives the ready marker, and closes the write end of the pipe in response (after_fork_in_parent).

After this sequence of steps, an exit (whether clean or not) of the child will result in the pipe being marked readable again, and giving an EOF marker (nil) when read. Note that closing of the unused ends of the pipe in the parent and child processes is essential in order for the EOF to be correctly triggered. The ready marker mechanism is used because there’s no easy hook for after_fork in the parent process.

Constant Summary collapse

READY_MARKER =
"READY"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePipe

Returns a new instance of Pipe.



51
52
53
54
55
56
57
58
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 51

def initialize
  @out, @in = IO.pipe
  if defined?(::Encoding::ASCII_8BIT)
    @in.set_encoding(::Encoding::ASCII_8BIT)
  end
  @last_read = Time.now
  @parent_pid = $$
end

Instance Attribute Details

#inObject

Returns the value of attribute in.



48
49
50
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 48

def in
  @in
end

#last_readObject (readonly)

Returns the value of attribute last_read.



49
50
51
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 49

def last_read
  @last_read
end

#outObject

Returns the value of attribute out.



48
49
50
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 48

def out
  @out
end

#parent_pidObject (readonly)

Returns the value of attribute parent_pid.



49
50
51
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 49

def parent_pid
  @parent_pid
end

Instance Method Details

#after_fork_in_childObject



79
80
81
82
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 79

def after_fork_in_child
  @out.close unless @out.closed?
  write(READY_MARKER)
end

#after_fork_in_parentObject



84
85
86
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 84

def after_fork_in_parent
  @in.close unless @in.closed?
end

#closeObject



60
61
62
63
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 60

def close
  @out.close unless @out.closed?
  @in.close unless @in.closed?
end

#closed?Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 88

def closed?
  @out.closed? && @in.closed?
end

#readObject



73
74
75
76
77
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 73

def read
  @in.close unless @in.closed?
  @last_read = Time.now
  @out.gets("\n\n")
end

#write(data) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/new_relic/agent/pipe_channel_manager.rb', line 65

def write(data)
  @out.close unless @out.closed?
  @in << NewRelic::LanguageSupport.with_cautious_gc do
    Marshal.dump(data)
  end
  @in << "\n\n"
end