<commit_before>"""Monitor subprocesses for completion (via signal(3))"""

from __future__ import absolute_import

__all__ = ["active_popen", "add_popen"]

class ChildrenMonitor(object):
  """Monitor subprocesses."""

  def __init__(self):
    """Initialise subprocess monitor."""
    from signal import signal, SIGCHLD

    self._pid_map = {}
    signal(SIGCHLD, self._signal)

  def __len__(self):
    """Number of active subprocesses."""
    return len(self._pid_map)

  def add_popen(self, popen, callback):
    """Add a popen instance to be monitored, with callback function."""
    from subprocess import Popen

    if isinstance(popen, Popen):
      self._pid_map[popen.pid] = (popen, callback)
    else:
      from .event import post_event
      post_event(callback, popen)

  def _signal(self, _signum, _frame):
    """Handle a signal from child process."""
    from os import waitpid, WNOHANG
    from .event import post_event

    try:
      while True:
        pid, status = waitpid(-1, WNOHANG)
        if not pid:
          break

        if status & 0xff:
          # If low byte set then process exited due to signal
          status = -(status & 0xff)
        else:
          # Else high byte contains exit status
          status = status >> 8
        post_event(self._process_signal, pid, status)
    except OSError:
      pass

  def _process_signal(self, pid, status):
    """Update the subprocess object and dispatch the callback."""
    from .event import post_event

    popen, callback = self._pid_map.pop(pid)
    popen.returncode = status

    post_event(callback, popen)

_monitor = ChildrenMonitor()

active_popen = _monitor.__len__
add_popen = _monitor.add_popen
<commit_msg>  - add ability to retrieve all active subprocesses<commit_after>"""Monitor subprocesses for completion (via signal(3))"""

from __future__ import absolute_import

__all__ = ["active_popen", "add_popen", "children"]

class ChildrenMonitor(object):
  """Monitor subprocesses."""

  def __init__(self):
    """Initialise subprocess monitor."""
    from signal import signal, SIGCHLD

    self._pid_map = {}
    signal(SIGCHLD, self._signal)

  def __len__(self):
    """Number of active subprocesses."""
    return len(self._pid_map)

  def add_popen(self, popen, callback):
    """Add a popen instance to be monitored, with callback function."""
    from subprocess import Popen

    if isinstance(popen, Popen):
      self._pid_map[popen.pid] = (popen, callback)
    else:
      from .event import post_event
      post_event(callback, popen)

  def children(self):
    """Returns all the current children."""
    return self._pid_map.keys()

  def _signal(self, _signum, _frame):
    """Handle a signal from child process."""
    from os import waitpid, WNOHANG
    from .event import post_event

    try:
      while True:
        pid, status = waitpid(-1, WNOHANG)
        if not pid:
          break

        if status & 0xff:
          # If low byte set then process exited due to signal
          status = -(status & 0xff)
        else:
          # Else high byte contains exit status
          status = status >> 8
        post_event(self._process_signal, pid, status)
    except OSError:
      pass

  def _process_signal(self, pid, status):
    """Update the subprocess object and dispatch the callback."""
    from .event import post_event

    popen, callback = self._pid_map.pop(pid)
    popen.returncode = status

    post_event(callback, popen)

_monitor = ChildrenMonitor()

active_popen = _monitor.__len__
add_popen    = _monitor.add_popen
children     = _monitor.children

{'fraction_non_alphanumeric': 0.09796827163929864, 'fraction_numerical': 0.0027831895352073478, 'mean_word_length': 2.993333333333333, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '2841042', 'n_tokens_mistral': 1093, 'n_tokens_neox': 1051, 'n_words': 339}