module Fluent::PluginHelper::ChildProcess

def child_process_execute(

On Windows, exitstatus=0 and termsig=nil even when child process was killed.
status is an instance of Process::Status
on_exit_callback = ->(status){ ... }
def child_process_execute(
    title, command,
    arguments: nil, subprocess_name: nil, interval: nil, immediate: false, parallel: false,
    mode: [:read, :write], stderr: :discard, env: {}, unsetenv: false, chdir: nil,
    internal_encoding: 'utf-8', external_encoding: 'ascii-8bit', scrub: true, replace_string: nil,
    wait_timeout: nil, on_exit_callback: nil,
    &block
)
  raise ArgumentError, "BUG: title must be a symbol" unless title.is_a? Symbol
  raise ArgumentError, "BUG: arguments required if subprocess name is replaced" if subprocess_name && !arguments
  mode ||= []
  mode = [] unless block
  raise ArgumentError, "BUG: invalid mode specification" unless mode.all?{|m| MODE_PARAMS.include?(m) }
  raise ArgumentError, "BUG: read_with_stderr is exclusive with :read and :stderr" if mode.include?(:read_with_stderr) && (mode.include?(:read) || mode.include?(:stderr))
  raise ArgumentError, "BUG: invalid stderr handling specification" unless STDERR_OPTIONS.include?(stderr)
  raise ArgumentError, "BUG: number of block arguments are different from size of mode" if block && block.arity != mode.size
  running = false
  callback = ->(*args) {
    running = true
    begin
      block && block.call(*args)
    ensure
      running = false
    end
  }
  retval = nil
  execute_child_process = ->(){
    child_process_execute_once(
      title, command, arguments,
      subprocess_name, mode, stderr, env, unsetenv, chdir,
      internal_encoding, external_encoding, scrub, replace_string,
      wait_timeout, on_exit_callback,
      &callback
    )
  }
  if immediate || !interval
    retval = execute_child_process.call
  end
  if interval
    timer_execute(:child_process_execute, interval, repeat: true) do
      if !parallel && running
        log.warn "previous child process is still running. skipped.", title: title, command: command, arguments: arguments, interval: interval, parallel: parallel
      else
        execute_child_process.call
      end
    end
  end
  retval # nil if interval
end