Skip to content

Implement Pipe-Based Synchronization Between Parent and Child Processes #77

@dustinblack

Description

@dustinblack

In a multi-process benchmark using fork(), it is critical to ensure the parent (client) process does not
attempt to connect or send messages before the child (server) process has completed its initialization.

To make our benchmark robust and reliable, we must implement a deterministic synchronization mechanism.

Proposed Solution

A standard and highly effective method for this is to use a pipe. The pipe() system call (available via the nix
crate) creates a pair of connected file descriptors, which can be used for one-way communication.

The synchronization flow should be as follows:

  1. Before Fork: The main process creates a pipe using nix::unistd::pipe().
  2. After Fork:
    • The parent process (client) closes the write end of the pipe.
    • The child process (server) closes the read end of the pipe.
  3. Child Process Logic:
    • The child proceeds to initialize the server-side transport (transport.start_server()).
    • If initialization is successful, the child writes a single byte to its write end of the pipe and then
      closes it.
    • If initialization fails, the child logs the error and exits immediately without writing to the pipe.
  4. Parent Process Logic:
    • The parent process immediately attempts a blocking read() on its read end of the pipe.
    • If the read() call returns successfully (with one byte), the parent knows the child is ready and can
      proceed with its client-side logic (transport.start_client()).
    • If the read() call returns 0 (EOF), it means the child closed its end of the pipe without writing. The
      parent should interpret this as a failure, wait() for the child to collect its exit status, and terminate
      the benchmark for that mechanism.

Acceptance Criteria

  • A pipe is created before the fork() call in the BenchmarkRunner.
  • The parent process blocks on read() from the pipe before it attempts to initialize its client transport.
  • The child process writes a byte to the pipe only after its server transport has been successfully
    initialized.
  • If the child process fails to initialize, the parent process correctly detects the failure via the pipe
    and aborts the test for that mechanism.
  • The synchronization mechanism is implemented for all IPC mechanisms running under the multi-process model.
  • The old usleep() or any other non-deterministic delay for synchronization is removed.

Context

This is a high-priority task (P2) for ensuring the reliability and correctness of the benchmark suite.

This task is dependent on the completion of the multi-process refactoring (Issue #74). The
synchronization logic will be built into the new fork()-based execution flow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Priority 2 (nice to have or refinement)enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions