Remove the separate reporting process in gentest.pl and use the main process for the purpose

Registered by Philip Stoev

It is possible to use the main gentest.pl process to start and manage the Reporters. This way, one extra fork() (always a cause of issues on various platforms) is avoided and the code becomes much simpler.

Blueprint information

Status:
Not started
Approver:
None
Priority:
Undefined
Drafter:
None
Direction:
Needs approval
Assignee:
None
Definition:
New
Series goal:
None
Implementation:
Unknown
Milestone target:
None

Related branches

Sprints

Whiteboard

The body of the code should be redesigned along those lines:

foreach my $i (1..$threads) {
 my $child_pid = fork();
 if ($child_pid == 0) { # This is a child
  $process_type = PROCESS_TYPE_CHILD;
  last;
 } else {
  $child_pids{$child_pid} = 1;
  $process_type = PROCESS_TYPE_PARENT;
  $seed++;
  $id++;
  Time::HiRes::sleep(0.1); # fork slowly for more predictability
 }
}

if ($process_type == PROCESS_TYPE_PARENT) {
 # We are the parent process, wait for for all spawned processes to terminate
 my $children_died = 0;
 my $total_status = STATUS_OK;
 my $last_periodic = 0;
 my (@incidents, @statuses);

 while (1) {
  Time::HiRes::sleep(0.1);
  while (my $child_pid = waitpid(-1, WNOHANG)) {
   my $exit_status = $? > 0 ? ($? >> 8) : 0;
   $total_status = $exit_status if $exit_status > $total_status;
   $children_died++;
   delete $child_pids{$child_pid};

   last if $exit_status >= STATUS_CRITICAL_FAILURE;
   last if $children_died == $threads;
   last if $child_pid == -1;
  }

  last if $ctrl_c == 1;

  if (time() - $last_periodic >= 10) {
   my @periodic_results = $reporter_manager->monitor(REPORTER_TYPE_PERIODIC);
   my $periodic_status = shift @periodic_results;
   $total_status = $periodic_status if $periodic_status > $total_status;

   push @incidents , grep { ref($_) eq 'GenTest::Incident' } @periodic_results;
   push @statuses , grep { ref($_) eq 'GenTest::Status' } @periodic_results;

   $last_periodic = time();
  }

  last if $total_status > STATUS_CRITICAL_FAILURE;
 }

 foreach my $child_pid (keys %child_pids) {
  say("Killing child process with pid $child_pid...");
  kill(15, $child_pid);
 }

 my @report_results;

 if ($total_status == STATUS_OK) {
  @report_results = $reporter_manager->report(REPORTER_TYPE_SUCCESS | REPORTER_TYPE_ALWAYS);
 } elsif (
  ($total_status == STATUS_LENGTH_MISMATCH) ||
  ($total_status == STATUS_CONTENT_MISMATCH)
 ) {
  @report_results = $reporter_manager->report(REPORTER_TYPE_DATA);
 } elsif ($total_status == STATUS_SERVER_CRASHED) {
  say("Server crash reported, initiating post-crash analysis...");
  @report_results = $reporter_manager->report(REPORTER_TYPE_CRASH | REPORTER_TYPE_ALWAYS);
 } elsif ($total_status == STATUS_SERVER_DEADLOCKED) {
  say("Server deadlock reported, initiating analysis...");
  @report_results = $reporter_manager->report(REPORTER_TYPE_DEADLOCK | REPORTER_TYPE_ALWAYS);
 } elsif ($total_status == STATUS_SERVER_KILLED) {
  @report_results = $reporter_manager->report(REPORTER_TYPE_SERVER_KILLED | REPORTER_TYPE_ALWAYS);
 } else {
  @report_results = $reporter_manager->report(REPORTER_TYPE_ALWAYS);
 }

 my $report_status = shift @report_results;
 $total_status = $report_status if $report_status > $total_status;
 $total_status = STATUS_OK if $total_status == STATUS_SERVER_KILLED;

 push @incidents, grep { ref($_) eq 'GenTest::Incident' } @report_results;
 push @statuses, grep { ref($_) eq 'GenTest::Status' } @report_results;

 foreach my $incident (@incidents) {
  $test->addIncident($incident);
 }

 foreach my $status (@statuses) {
  $test->addStatus($status);
 }

 $test->end($total_status == STATUS_OK ? "pass" : "fail");

 if (defined $xml_output) {
  open (XML , ">$xml_output") or say("Unable to open $xml_output: $!");
  print XML $report->xml();
  close XML;
 }

 if ($total_status == STATUS_OK) {
  say("Test completed successfully.");
 } else {
  say("Test completed with failure status $total_status.");
 }

 safe_exit($total_status);
} elsif ($process_type == PROCESS_TYPE_CHILD) {

(?)

Work Items

This blueprint contains Public information 
Everyone can see this information.

Subscribers

No subscribers.