Class: Mutant::Isolation::Fork Private

Inherits:
Mutant::Isolation show all
Includes:
Unparser::Adamantium
Defined in:
lib/mutant/isolation/fork.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Isolation via the fork(2) systemcall.

Communication between parent and child process is done via anonymous pipes.

Timeouts are initially handled relatively efficiently via IO.select but once the child process pipes are on eof via busy looping on waitpid2 with Process::WNOHANG set.

Handling timeouts this way is not the conceptually most efficient solution. But its cross platform.

Design constraints:

  • Support Linux

  • Support MacOSX

  • Avoid platform specific APIs and code.

  • Only use ruby corelib.

  • Do not use any named resource.

  • Never block on latency inducing systemcall without a timeout.

  • Child process freezing before closing the pipes needs to be detected by parent process.

  • Child process freezing after closing the pipes needs to be detected by parent process.

Defined Under Namespace

Classes: Child, Parent, Pipe

Constant Summary collapse

READ_SIZE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

4096
ATTRIBUTES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%i[block deadline log_pipe result_pipe world].freeze

Instance Method Summary collapse

Instance Method Details

#call(timeout, &block) ⇒ Result

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Call block in isolation

rubocop:disable Metrics/MethodLength

Returns:



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/mutant/isolation/fork.rb', line 233

def call(timeout, &block)
  deadline = world.deadline(timeout)
  io = world.io
  Pipe.with(io) do |result|
    Pipe.with(io) do |log|
      Parent.call(
        block:,
        deadline:,
        log_pipe:    log,
        result_pipe: result,
        world:
      )
    end
  end
end