def cleanup(self):
        r"""
        Cleanup after the run method.
        """

        try:
            gp.lprint_executing()
            gp.lprint_var(self.__child_pid)
        except (AttributeError, KeyError, TypeError):
            # NOTE: In python 3, this code fails with "KeyError:
            # ('__main__',)" when calling functions like lprint_executing that
            # use inspect.stack() during object destruction.  No fixes found
            # so tolerating the error.  In python 2.x, it may fail with
            # TypeError.  This seems to happen when cleaning up after an
            # exception was raised.
            pass

        # If self.__child_pid is 0, then we are either running as the child
        # or we've already cleaned up.
        # If self.__time_out is None, then no child process would have been
        # spawned.
        if self.__child_pid == 0 or self.__time_out is None:
            return

        # Restore the original SIGUSR1 handler.
        if self.__original_SIGUSR1_handler != 0:
            signal.signal(signal.SIGUSR1, self.__original_SIGUSR1_handler)
        try:
            gp.lprint_timen("Killing child pid " + str(self.__child_pid) + ".")
            os.kill(self.__child_pid, signal.SIGKILL)
        except OSError:
            gp.lprint_timen("Tolerated kill failure.")
        try:
            gp.lprint_timen("os.waitpid(" + str(self.__child_pid) + ")")
            os.waitpid(self.__child_pid, 0)
        except OSError:
            gp.lprint_timen("Tolerated waitpid failure.")
        self.__child_pid = 0
        # For debug purposes, prove that the child pid was killed.
        children = gm.get_child_pids()
        gp.lprint_var(children)
示例#2
0
    def cleanup(self):
        r"""
        Cleanup after the run method.
        """

        try:
            gp.lprint_executing()
            gp.lprint_var(self.__child_pid)
        except AttributeError:
            pass

        # If self.__child_pid is 0, then we are either running as the child
        # or we've already cleaned up.
        # If self.__time_out is None, then no child process would have been
        # spawned.
        if self.__child_pid == 0 or self.__time_out is None:
            return

        # Restore the original SIGUSR1 handler.
        if self.__original_SIGUSR1_handler != 0:
            signal.signal(signal.SIGUSR1, self.__original_SIGUSR1_handler)
        try:
            gp.lprint_timen("Killing child pid " + str(self.__child_pid)
                            + ".")
            os.kill(self.__child_pid, signal.SIGKILL)
        except OSError:
            gp.lprint_timen("Tolerated kill failure.")
        try:
            gp.lprint_timen("os.waitpid(" + str(self.__child_pid) + ")")
            os.waitpid(self.__child_pid, 0)
        except OSError:
            gp.lprint_timen("Tolerated waitpid failure.")
        self.__child_pid = 0
        # For debug purposes, prove that the child pid was killed.
        children = gm.get_child_pids()
        gp.lprint_var(children)
示例#3
0
    def run(self, func, *args, **kwargs):

        r"""
        Run the indicated function with the given args and kwargs and return
        the value that the function returns.  If the time_out value expires,
        raise a ValueError exception with a detailed error message.

        This method passes all of the args and kwargs directly to the child
        function with the following important exception: If kwargs contains a
        'time_out' value, it will be used to set the func timer object's
        time_out value and then the kwargs['time_out'] entry will be removed.
        If the time-out expires before the function finishes running, this
        method will raise a ValueError.

        Example:
        func_timer = func_timer_class()
        func_timer.run(run_key, "sleep 3", time_out=2)

        Example:
        try:
            result = func_timer.run(func1, "parm1", time_out=2)
            print_var(result)
        except ValueError:
            print("The func timed out but we're handling it.")

        Description of argument(s):
        func                        The function object which is to be called.
        args                        The arguments which are to be passed to
                                    the function object.
        kwargs                      The keyword arguments which are to be
                                    passed to the function object.  As noted
                                    above, kwargs['time_out'] will get special
                                    treatment.
        """

        gp.lprint_executing()

        # Store method parms as object parms.
        self.__func = func

        # Get self.__time_out value from kwargs.  If kwargs['time_out'] is
        # not present, self.__time_out will default to None.
        self.__time_out = None
        if 'time_out' in kwargs:
            self.__time_out = kwargs['time_out']
            del kwargs['time_out']
            # Convert "none" string to None.
            try:
                if self.__time_out.lower() == "none":
                    self.__time_out = None
            except AttributeError:
                pass
            if self.__time_out is not None:
                self.__time_out = int(self.__time_out)
                # Ensure that time_out is non-negative.
                message = gv.svalid_range(self.__time_out, [0], "time_out")
                if message != "":
                    raise ValueError("\n"
                                     + gp.sprint_error_report(message,
                                                              format='long'))

        gp.lprint_varx("time_out", self.__time_out)
        self.__child_pid = 0
        if self.__time_out is not None:
            # Save the original SIGUSR1 handler for later restoration by this
            # class' methods.
            self.__original_SIGUSR1_handler = signal.getsignal(signal.SIGUSR1)
            # Designate a SIGUSR1 handling function.
            signal.signal(signal.SIGUSR1, self.timed_out)
            parent_pid = os.getpid()
            self.__child_pid = os.fork()
            if self.__child_pid == 0:
                gp.dprint_timen("Child timer pid " + str(os.getpid())
                                + ": Sleeping for " + str(self.__time_out)
                                + " seconds.")
                time.sleep(self.__time_out)
                gp.dprint_timen("Child timer pid " + str(os.getpid())
                                + ": Sending SIGUSR1 to parent pid "
                                + str(parent_pid) + ".")
                os.kill(parent_pid, signal.SIGUSR1)
                os._exit(0)

        # Call the user's function with the user's arguments.
        children = gm.get_child_pids()
        gp.lprint_var(children)
        gp.lprint_timen("Calling the user's function.")
        gp.lprint_varx("func_name", func.__name__)
        gp.lprint_vars(args, kwargs)
        try:
            result = func(*args, **kwargs)
        except Exception as func_exception:
            # We must handle all exceptions so that we have the chance to
            # cleanup before re-raising the exception.
            gp.lprint_timen("Encountered exception in user's function.")
            self.cleanup()
            raise(func_exception)
        gp.lprint_timen("Returned from the user's function.")

        self.cleanup()

        return result