示例#1
0
def stop_doppelgänger(pid_path="/tmp/menu.pid"):

    if os.path.isfile(pid_path):
        if os.path.isfile(pid_path):
            with open(pid_path, "r") as f:
                pid = int(f.read())

            try:
                twin = Process(pid)
                twin.send_signal(signal.SIGTERM)
                print(f"our twin {twin.pid} was stopped", flush=True)
                twin.wait(timeout=5)
            except psutil.NoSuchProcess as e:
                pass
            except psutil.TimeoutExpired as e:
                print(f"Timeout expired; exiting.", flush=True)
                sys.exit(10)
            except OSError as e:
                # errno.ESRCH unimportant: sometimes the /tmp/menu.pid is stale
                if e.errno == errno.ESRCH:
                    print(f"no such process which is ok.")
                else:
                    print(f"Unexpected OSError {e}")
            except Exception as e:
                print(f"Unexpected exception {e}")

    this_pid = psutil.Process()
    with open(pid_path, "w") as f:
        f.write(str(this_pid.pid))
    return this_pid.pid
示例#2
0
 def kill(self, p: psutil.Process):
     if sys.platform == "win32":
         import ctypes
         kernel = ctypes.windll.kernel32
         kernel.FreeConsole()
         kernel.AttachConsole(p.pid)
         kernel.SetConsoleCtrlHandler(None, 1)
         kernel.GenerateConsoleCtrlEvent(0, 0)
         sys.exit(0)
     import signal
     p.send_signal(signal.SIGINT)
示例#3
0
    def kill_process(
        self,
        process: psutil.Process,
        signal: int,
    ) -> None:
        try:
            self.logger.info(msg='kill_process request', )

            process.send_signal(sig=signal, )
        except Exception as exception:
            self.logger.error(msg=str(exception), )
示例#4
0
 def doKillChild(child: psutil.Process, sig: int):
     Logging.info("Killing sub-sub process {} with signal {}".format(child.pid, sig))
     child.send_signal(sig)
     try:            
         retCode = child.wait(20) # type: ignore
         if (- retCode) == signal.SIGSEGV: # type: ignore # Crashed
             Logging.warning("Process {} CRASHED, please check CORE file!".format(child.pid))
         elif (- retCode) == sig : # type: ignore
             Logging.info("Sub-sub process terminated with expected return code {}".format(sig))
         else:
             Logging.warning("Process terminated, EXPECTING ret code {}, got {}".format(sig, -retCode)) # type: ignore
         return True # terminated successfully
     except psutil.TimeoutExpired as err:
         Logging.warning("Failed to kill sub-sub process {} with signal {}".format(child.pid, sig))
     return False # did not terminate
示例#5
0
def _kill(pid, timeout=1.5):
    try:
        process = Process(pid)
    except NoSuchProcess:
        return
    try:
        process.send_signal(SIGINT)
        sleep(timeout)
    except OSError:
        pass
    finally:
        try:
            process.send_signal(SIGKILL)
        except (OSError, NoSuchProcess):
            pass
        process.wait()
示例#6
0
def _kill(pid, timeout=1.5):
    try:
        process = Process(pid)
    except NoSuchProcess:
        return
    try:
        process.send_signal(SIGINT)
        sleep(timeout)
    except OSError:
        pass
    finally:
        try:
            process.send_signal(SIGKILL)
        except (OSError, NoSuchProcess):
            pass
        process.wait()
示例#7
0
    def test_sigint(self):
        '''
        Setup test server sleep 0.01 for each request
        Start spider in separate python shell (untill sigin
            or max 200 requests)
        Wait 1 sec (~100 requests, in reality less
            because of process start-up time)
        Send SIGINT to the process
        Check it returned with 13 or 139 codes
        139 code means segfault (yeah...o_O) But as I see from logs
            it segfaults after successfully processing the SIGINT and
            this is all I need from this test
        '''
        #logging.error('step-0')
        # pylint: disable=no-member
        self.server.response['sleep'] = 0.01
        # pylint: enable=no-member
        with temp_file() as path:
            with open(path, 'w') as out:
                # pylint: disable=no-member
                out.write(self.script_tpl % ('', self.server.get_url()))
                # pylint: enable=no-member
            ret_codes = []
            for _ in range(10):
                #logging.error('step-1')
                proc = Popen('python %s' % path, shell=True)
                #logging.error('step-2')
                parent = Process(proc.pid)
                #logging.error('step-3')
                time.sleep(1)
                #logging.error('killing children')
                for child in parent.children():
                    #logging.error('CHILD: %s', child.pid)
                    # Sending multiple SIGINTs
                    # because in very rare cases the only
                    # sigint signals is ignored :-/
                    # do not send too fast
                    for _ in range(1):
                        try:
                            #logging.error('sending sigint')
                            child.send_signal(SIGNAL_INT)
                        except NoSuchProcess:
                            break
                        else:
                            time.sleep(1)
                if platform.system() == 'Darwin':
                    # On OSX the Popen(shell=True) spawns only
                    # one process, no child
                    #logging.error('Killing parent')
                    #logging.error('PARENT: %s', parent.pid)
                    # Sending multiple SIGINTs
                    # because in very rare cases the only
                    # sigint signals is ignored :-/
                    # do not send too fast
                    for _ in range(1):
                        try:
                            #logging.error('sending sigint')
                            parent.send_signal(SIGNAL_INT)
                        except NoSuchProcess:
                            break
                        else:
                            time.sleep(1)
                #logging.error('step-4')
                ret = None
                for _ in range(20):
                    #print('before proc-poll-%d' % step)
                    ret = proc.poll()
                    if ret is not None:
                        break
                    time.sleep(0.1)
                else:
                    #logging.error('CHILD PROCESS DID NOT RETURN')
                    #raise Exception('Child process did not return')
                    # try to clean processes
                    try:
                        for child in parent.children():
                            child.send_signal(signal.SIGTERM)
                    except NoSuchProcess:
                        pass
                    time.sleep(0.5)
                    try:
                        parent.send_signal(signal.SIGTERM)
                    except NoSuchProcess:
                        pass
                #logging.error('step-5')
                # FIXME: find out the reasonf of segfault
                # the 130 signal means the program was terminated by ctrl-c
                #print('RET CODE: %s' % ret)
                ret_codes.append(ret)

            # Could fail in 10% (1 of 10)
            # pylint: disable=no-member
            self.assertTrue(sum(1 for x in ret_codes
                                if x in (13, 130, 139)) >= 9)
示例#8
0
    def test_sigint(self):
        '''
        Setup test server sleep 0.01 for each request
        Start spider in separate python shell (untill sigin
            or max 200 requests)
        Wait 1 sec (~100 requests, in reality less
            because of process start-up time)
        Send SIGINT to the process
        Check it returned with 13 or 139 codes
        139 code means segfault (yeah...o_O) But as I see from logs
            it segfaults after successfully processing the SIGINT and
            this is all I need from this test
        '''
        #logging.error('step-0')
        # pylint: disable=no-member
        self.server.response['sleep'] = 0.01
        # pylint: enable=no-member
        with temp_file() as path:
            with open(path, 'w') as out:
                # pylint: disable=no-member
                out.write(self.script_tpl % ('', self.server.get_url()))
                # pylint: enable=no-member
            ret_codes = []
            for _ in range(10):
                #logging.error('step-1')
                proc = Popen('python %s' % path, shell=True)
                #logging.error('step-2')
                parent = Process(proc.pid)
                #logging.error('step-3')
                time.sleep(1)
                #logging.error('killing children')
                for child in parent.children():
                    #logging.error('CHILD: %s', child.pid)
                    # Sending multiple SIGINTs
                    # because in very rare cases the only
                    # sigint signals is ignored :-/
                    # do not send too fast
                    for _ in range(1):
                        try:
                            #logging.error('sending sigint')
                            child.send_signal(SIGNAL_INT)
                        except NoSuchProcess:
                            break
                        else:
                            time.sleep(1)
                if platform.system() == 'Darwin':
                    # On OSX the Popen(shell=True) spawns only
                    # one process, no child
                    #logging.error('Killing parent')
                    #logging.error('PARENT: %s', parent.pid)
                    # Sending multiple SIGINTs
                    # because in very rare cases the only
                    # sigint signals is ignored :-/
                    # do not send too fast
                    for _ in range(1):
                        try:
                            #logging.error('sending sigint')
                            parent.send_signal(SIGNAL_INT)
                        except NoSuchProcess:
                            break
                        else:
                            time.sleep(1)
                #logging.error('step-4')
                ret = None
                for _ in range(20):
                    #print('before proc-poll-%d' % step)
                    ret = proc.poll()
                    if ret is not None:
                        break
                    time.sleep(0.1)
                else:
                    #logging.error('CHILD PROCESS DID NOT RETURN')
                    #raise Exception('Child process did not return')
                    # try to clean processes
                    try:
                        for child in parent.children():
                            child.send_signal(signal.SIGTERM)
                    except NoSuchProcess:
                        pass
                    time.sleep(0.5)
                    try:
                        parent.send_signal(signal.SIGTERM)
                    except NoSuchProcess:
                        pass
                #logging.error('step-5')
                # FIXME: find out the reasonf of segfault
                # the 130 signal means the program was terminated by ctrl-c
                #print('RET CODE: %s' % ret)
                ret_codes.append(ret)

            # Could fail in 10% (1 of 10)
            # pylint: disable=no-member
            self.assertTrue(sum(1 for x in ret_codes
                                if x in (13, 130, 139)) >= 9)
示例#9
0
文件: utils.py 项目: Xowap/Spybar
class SpyProcess:
    """
    Spying process to detect the currently open files and their current reading
    advancement.

    Notes
    -----
    There is three threads at play here:

    - The main thread, which handles the display
    - The ticking thread which drives refreshing
    - The process watching thread, which waits for the process to be done

    Both the ticking and the process threads communicate their ticks to the
    main thread through a queue. This way the main thread can easily display
    an update every second and close instantly when the process is done.
    """
    def __init__(self,
                 args: Sequence[Text],
                 period: float,
                 output: Output,
                 attach=Optional[int]):
        self.args = args
        self.attach = attach
        self.proc: Optional[Popen] = None
        self.files_cache = {}
        self.display_ticks = Queue()
        self.process_thread = Thread(target=self.watch_process)
        self.ticks_thread = Thread(target=self.generate_ticks,
                                   args=(period, ),
                                   daemon=True)
        self.progress = Progress(output)
        self.counters = {}

    def start(self):
        """
        If a PID was supplied to attach in the CLI options then use it.
        Otherwise use the provided arguments to start the command.
        """

        if self.attach is None:
            try:
                self.proc = Popen(self.args)
            except FileNotFoundError:
                stderr.write(f'Could not find command "{self.args[0]}"\n')
                exit(1)
        else:
            try:
                self.proc = Process(self.attach)
            except (AccessDenied, NoSuchProcess):
                stderr.write(
                    f"Could not attach process {self.attach}. Does it exist? "
                    f"Do you have the rights?\n")
                exit(1)

    def open_files(self) -> List[popenfile]:
        """
        Returns the list of open files
        """

        return self.proc.open_files()

    def list_files(self) -> Sequence[FileInfo]:
        """
        Generates the FileInfo object of all interesting files.
        """

        files_in_use = set()
        out = []

        try:
            for f in self.open_files():
                if f.mode != "r":
                    continue

                files_in_use.add(f.path)

                if f.path not in self.files_cache:
                    self.files_cache[f.path] = path.getsize(f.path)

                if hasattr(f, "position"):
                    out.append(
                        FileInfo(
                            path=f.path,
                            size=self.files_cache[f.path],
                            position=f.position,
                        ))
        except (AccessDenied, NoSuchProcess):
            pass

        for k in set(self.files_cache.keys()) - files_in_use:
            del self.files_cache[k]

        return out

    def print_progress(self):
        """
        UI display thread, looping around until the thing is done
        """

        stop = False

        try:
            while not stop:
                files = self.list_files()
                self.progress.update(files)
                stop = self.display_ticks.get()
        finally:
            self.progress.close()

    def generate_ticks(self, period: float):
        """
        Ticks into the queue every "period" second

        Parameters
        ----------
        period
            Number of seconds between two ticks
        """

        while True:
            self.display_ticks.put(False)
            sleep(period)

    def start_display(self):
        """
        Starts the threads that will tick the display
        """

        self.ticks_thread.start()
        self.process_thread.start()
        self.print_progress()

    def watch_process(self):
        """
        Waits until the process finishes and raises the tick
        """

        self.return_code()
        self.display_ticks.put(True)

    def return_code(self) -> int:
        """
        Waits for the process to finish and returns its return code
        """

        return self.proc.wait()

    def send_signal(self, sig):
        """
        Sends a signal to the child process

        Parameters
        ----------
        sig
            Unix signal
        """

        try:
            self.proc.send_signal(sig)
        except NoSuchProcess:
            pass