<commit_before>/// \file procs.cpp
/// Contains generic functions for managing processes.

#include "procs.h"
#include <string.h>
#include <sys/types.h>
#include <signal.h>

#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
#include <sys/wait.h>
#else
#include <wait.h>
#endif
#include <errno.h>
#include <iostream>
#include <sys/types.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include "timing.h"

std::map<pid_t, std::string> Util::Procs::plist;
std::map<pid_t, Util::TerminationNotifier> Util::Procs::exitHandlers;
bool Util::Procs::handler_set = false;

/// Called at exit of any program that used a Start* function.
/// Waits up to 2.5 seconds, then sends SIGINT signal to all managed processes.
/// After that waits up to 10 seconds for children to exit, then sends SIGKILL to
/// all remaining children. Waits one more second for cleanup to finish, then exits.
void Util::Procs::exit_handler(){
  int waiting = 0;
  while ( !plist.empty()){
    Util::sleep(100);
    if (++waiting > 25){
      break;
    }
  }
  
  if ( !plist.empty()){
    std::map<pid_t, std::string> listcopy = plist;
    std::map<pid_t, std::string>::iterator it;
    for (it = listcopy.begin(); it != listcopy.end(); it++){
      kill(( *it).first, SIGINT);
    }
  }

  waiting = 0;
  while ( !plist.empty()){
    Util::sleep(200);
    if (++waiting > 25){
      break;
    }
  }

  if ( !plist.empty()){
    std::map<pid_t, std::string> listcopy = plist;
    std::map<pid_t, std::string>::iterator it;
    for (it = listcopy.begin(); it != listcopy.end(); it++){
      kill(( *it).first, SIGKILL);
    }
  }

  waiting = 0;
  while ( !plist.empty()){
    Util::sleep(100);
    if (++waiting > 10){
      break;
    }
  }
  
}

/// Sets up exit and childsig handlers.
/// Called by every Start* function.
void Util::Procs::setHandler(){
  if ( !handler_set){
    struct sigaction new_action;
    new_action.sa_handler = childsig_handler;
    sigemptyset( &new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    atexit(exit_handler);
    handler_set = true;
  }
}

/// Used internally to capture child signals and update plist.
void Util::Procs::childsig_handler(int signum){
  if (signum != SIGCHLD){
    return;<commit_msg>Fixed slow-working Util::Procs terminate handler.<commit_after>/// \file procs.cpp
/// Contains generic functions for managing processes.

#include "procs.h"
#include <string.h>
#include <sys/types.h>
#include <signal.h>

#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
#include <sys/wait.h>
#else
#include <wait.h>
#endif
#include <errno.h>
#include <iostream>
#include <sys/types.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include "timing.h"

std::map<pid_t, std::string> Util::Procs::plist;
std::map<pid_t, Util::TerminationNotifier> Util::Procs::exitHandlers;
bool Util::Procs::handler_set = false;

/// Called at exit of any program that used a Start* function.
/// Waits up to 1 second, then sends SIGINT signal to all managed processes.
/// After that waits up to 5 seconds for children to exit, then sends SIGKILL to
/// all remaining children. Waits one more second for cleanup to finish, then exits.
void Util::Procs::exit_handler(){
  int waiting = 0;
  std::map<pid_t, std::string> listcopy = plist;
  std::map<pid_t, std::string>::iterator it;

  //wait up to 1 second for applications to shut down 
  while ( !listcopy.empty() && waiting <= 50){
    for (it = listcopy.begin(); it != listcopy.end(); it++){
      if (kill(( *it).first, 0) == 0){
        Util::sleep(20);
        ++waiting;
      }else{
        listcopy.erase(it);
        break;
      }
    }
  }
  
  //send sigint to all remaining
  if ( !listcopy.empty()){
    for (it = listcopy.begin(); it != listcopy.end(); it++){
      kill(( *it).first, SIGINT);
    }
  }

  waiting = 0;
  //wait up to 5 seconds for applications to shut down 
  while ( !listcopy.empty() && waiting <= 50){
    for (it = listcopy.begin(); it != listcopy.end(); it++){
      if (kill(( *it).first, 0) == 0){
        Util::sleep(100);
        ++waiting;
      }else{
        listcopy.erase(it);
        break;
      }
    }
  }
  
  //send sigkill to all remaining
  if ( !plist.empty()){
    for (it = listcopy.begin(); it != listcopy.end(); it++){
      kill(( *it).first, SIGKILL);
    }
  }

  waiting = 0;
  //wait up to 1 second for applications to shut down 
  while ( !listcopy.empty() && waiting <= 50){
    for (it = listcopy.begin(); it != listcopy.end(); it++){
      if (kill(( *it).first, 0) == 0){
        Util::sleep(20);
        ++waiting;
      }else{
        listcopy.erase(it);
        break;
      }
    }
  }
  
}

/// Sets up exit and childsig handlers.
/// Called by every Start* function.
void Util::Procs::setHandler(){
  if ( !handler_set){
    struct sigaction new_action;
    new_action.sa_handler = childsig_handler;
    sigemptyset( &new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    atexit(exit_handler);
    handler_set = true;
  }
}

/// Used internally to capture child signals and update plist.
void Util::Procs::childsig_handler(int signum){
  if (signum != SIGCHLD){
    return;
{'fraction_non_alphanumeric': 0.16224412433661864, 'fraction_numerical': 0.009666413949962092, 'mean_word_length': 3.2216, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6148177', 'n_tokens_mistral': 1883, 'n_tokens_neox': 1804, 'n_words': 507}