Ejemplo n.º 1
0
    def _call_method(*args, **kwargs):
        """The new body for the decorated method.
        """
        if threadMgr.in_main_thread():
            # nothing special has to be done in the main thread
            func(*args, **kwargs)
            return

        GLib.idle_add(_idle_method, args, kwargs)
Ejemplo n.º 2
0
    def _call_method(*args, **kwargs):
        """The new body for the decorated method. If needed, it uses closure
           bound queue_instance variable which is valid until the reference to this
           method is destroyed."""
        if threadMgr.in_main_thread():
            # nothing special has to be done in the main thread
            return func(*args, **kwargs)

        GLib.idle_add(_idle_method, queue_instance, args, kwargs)
        return queue_instance.get()
Ejemplo n.º 3
0
    def _show_message_in_main_thread(self, msg_fn, args):
        """ If running in the main thread, run the message dialog function and
        return its return value. If running in a non-main thread, request the
        message function to be called in the main thread.

        :param msg_fn: message dialog function to be run
        :type msg_fn: a function taking the same number of arguments as is the
                      length of the args param
        :param args: arguments to be passed to the message dialog function
        :type args: any
        """

        if threadMgr.in_main_thread():
            # call the function directly
            return msg_fn(*args)
        else:
            # create a queue for the result returned by the function
            ret_queue = queue.Queue()

            # request the function to be called in the main thread
            self._send_show_message(msg_fn, args, ret_queue)

            # wait and return the result from the queue
            return ret_queue.get()
Ejemplo n.º 4
0
def gtk_batch_map(action, items, args=(), pre_func=None, batch_size=1):
    """
    Function that maps an action on items in a way that makes the action run in
    the main thread, but without blocking the main thread for a noticeable
    time. If a pre-processing function is given it is mapped on the items first
    before the action happens in the main thread.

    .. DANGER::
       MUST NOT BE CALLED NOR WAITED FOR FROM THE MAIN THREAD.

    :param action: any action that has to be done on the items in the main
                   thread
    :type action: (action_item, \\*args) -> None
    :param items: an iterable of items that the action should be mapped on
    :type items: iterable
    :param args: additional arguments passed to the action function
    :type args: tuple
    :param pre_func: a function that is mapped on the items before they are
                     passed to the action function
    :type pre_func: item -> action_item
    :param batch_size: how many items should be processed in one run in the main loop
    :raise AssertionError: if called from the main thread
    :return: None

    """

    assert(not threadMgr.in_main_thread())

    def preprocess(queue_instance):
        if pre_func:
            for item in items:
                queue_instance.put(pre_func(item))
        else:
            for item in items:
                queue_instance.put(item)

        queue_instance.put(TERMINATOR)

    def process_one_batch(arguments):
        (queue_instance, action, done_event) = arguments
        tstamp_start = time.time()
        tstamp = time.time()

        # process as many batches as user shouldn't notice
        while tstamp - tstamp_start < NOTICEABLE_FREEZE:
            for _i in range(batch_size):
                try:
                    action_item = queue_instance.get_nowait()
                    if action_item is TERMINATOR:
                        # all items processed, tell we are finished and return
                        done_event.set()
                        return False
                    else:
                        # run action on the item
                        action(action_item, *args)
                except queue.Empty:
                    # empty queue_instance, reschedule to run later
                    return True

            tstamp = time.time()

        # out of time but something left, reschedule to run again later
        return True

    item_queue_instance = queue.Queue()
    done_event = threading.Event()

    # we don't want to log the whole list, type and address is enough
    log.debug("Starting applying %s on %s", action, object.__repr__(items))

    # start a thread putting preprocessed items into the queue_instance
    threadMgr.add(AnacondaThread(prefix="AnaGtkBatchPre",
                                 target=preprocess,
                                 args=(item_queue_instance,)))

    GLib.idle_add(process_one_batch, (item_queue_instance, action, done_event))
    done_event.wait()
    log.debug("Finished applying %s on %s", action, object.__repr__(items))
Ejemplo n.º 5
0
    def handleException(self, dump_info):
        """
        Our own handleException method doing some additional stuff before
        calling the original python-meh's one.

        :type dump_info: an instance of the meh.DumpInfo class
        :see: python-meh's ExceptionHandler.handleException

        """

        log.debug("running handleException")
        exception_lines = traceback.format_exception(*dump_info.exc_info)
        log.critical("\n".join(exception_lines))

        ty = dump_info.exc_info.type
        value = dump_info.exc_info.value

        try:
            gi.require_version("Gtk", "3.0")

            from gi.repository import Gtk

            # XXX: Gtk stopped raising RuntimeError if it fails to
            # initialize. Horay! But will it stay like this? Let's be
            # cautious and raise the exception on our own to work in both
            # cases
            initialized = Gtk.init_check(None)[0]
            if not initialized:
                raise RuntimeError()

            # Attempt to grab the GUI initializing lock, do not block
            if not self._gui_lock.acquire(False):
                # the graphical interface is running, don't crash it by
                # running another one potentially from a different thread
                log.debug("Gtk running, queuing exception handler to the main loop")
                run_in_loop(self._main_loop_handleException, dump_info)
            else:
                log.debug("Gtk not running, starting Gtk and running exception handler in it")
                self._main_loop_handleException(dump_info)

        except (RuntimeError, ImportError, ValueError):
            log.debug("Gtk cannot be initialized")
            # X not running (Gtk cannot be initialized)
            if threadMgr.in_main_thread():
                log.debug("In the main thread, running exception handler")
                if issubclass(ty, NonInteractiveError) or not self._interactive:
                    if issubclass(ty, NonInteractiveError):
                        cmdline_error_msg = _("\nThe installation was stopped due to an "
                                              "error which occurred while running in "
                                              "non-interactive cmdline mode. Since there "
                                              "cannot be any questions in cmdline mode, edit "
                                              "your kickstart file and retry installation. "
                                              "\nThe exact error message is: \n\n%s. \n\nThe "
                                              "installer will now terminate.") % str(value)
                    else:
                        cmdline_error_msg = _("\nRunning in cmdline mode, no interactive "
                                              "debugging allowed.\nThe exact error message is: "
                                              "\n\n%s.\n\nThe installer will now terminate."
                                              ) % str(value)

                    # since there is no UI in cmdline mode and it is completely
                    # non-interactive, we can't show a message window asking the user
                    # to acknowledge the error; instead, print the error out and sleep
                    # for a few seconds before exiting the installer
                    print(cmdline_error_msg)
                    time.sleep(180)
                    sys.exit(1)
                else:
                    print("\nAn unknown error has occured, look at the "
                          "/tmp/anaconda-tb* file(s) for more details")
                    # in the main thread, run exception handler
                    self._main_loop_handleException(dump_info)
            else:
                log.debug("In a non-main thread, sending a message with exception data")
                # not in the main thread, just send message with exception
                # data and let message handler run the exception handler in
                # the main thread
                exc_info = dump_info.exc_info
                # new Simpleline package is now used in TUI. Look if Simpleline is
                # initialized or if this is some fallback from GTK or other stuff.
                if App.is_initialized():
                    # if Simpleline is initialized enqueue exception there
                    loop = App.get_event_loop()
                    loop.enqueue_signal(ExceptionSignal(App.get_scheduler(), exception_info=exc_info))
                else:
                    hubQ.send_exception((exc_info.type,
                                         exc_info.value,
                                         exc_info.stack))
Ejemplo n.º 6
0
    def handleException(self, dump_info):
        """
        Our own handleException method doing some additional stuff before
        calling the original python-meh's one.

        :type dump_info: an instance of the meh.DumpInfo class
        :see: python-meh's ExceptionHandler.handleException

        """

        log.debug("running handleException")
        exception_lines = traceback.format_exception(*dump_info.exc_info)
        log.critical("\n".join(exception_lines))

        ty = dump_info.exc_info.type
        value = dump_info.exc_info.value

        try:
            gi.require_version("Gtk", "3.0")

            from gi.repository import Gtk

            # XXX: Gtk stopped raising RuntimeError if it fails to
            # initialize. Horay! But will it stay like this? Let's be
            # cautious and raise the exception on our own to work in both
            # cases
            initialized = Gtk.init_check(None)[0]
            if not initialized:
                raise RuntimeError()

            # Attempt to grab the GUI initializing lock, do not block
            if not self._gui_lock.acquire(False):
                # the graphical interface is running, don't crash it by
                # running another one potentially from a different thread
                log.debug(
                    "Gtk running, queuing exception handler to the main loop")
                run_in_loop(self._main_loop_handleException, dump_info)
            else:
                log.debug(
                    "Gtk not running, starting Gtk and running exception handler in it"
                )
                self._main_loop_handleException(dump_info)

        except (RuntimeError, ImportError, ValueError):
            log.debug("Gtk cannot be initialized")
            # X not running (Gtk cannot be initialized)
            if threadMgr.in_main_thread():
                log.debug("In the main thread, running exception handler")
                if issubclass(ty,
                              NonInteractiveError) or not self._interactive:
                    if issubclass(ty, NonInteractiveError):
                        cmdline_error_msg = _(
                            "\nThe installation was stopped due to an "
                            "error which occurred while running in "
                            "non-interactive cmdline mode. Since there "
                            "cannot be any questions in cmdline mode, edit "
                            "your kickstart file and retry installation. "
                            "\nThe exact error message is: \n\n%s. \n\nThe "
                            "installer will now terminate.") % str(value)
                    else:
                        cmdline_error_msg = _(
                            "\nRunning in cmdline mode, no interactive "
                            "debugging allowed.\nThe exact error message is: "
                            "\n\n%s.\n\nThe installer will now terminate."
                        ) % str(value)

                    # since there is no UI in cmdline mode and it is completely
                    # non-interactive, we can't show a message window asking the user
                    # to acknowledge the error; instead, print the error out and sleep
                    # for a few seconds before exiting the installer
                    print(cmdline_error_msg, flush=True)
                    self._run_kickstart_scripts(dump_info)
                    util.ipmi_report(IPMI_FAILED)
                    time.sleep(180)
                    sys.exit(1)
                else:
                    print("\nAn unknown error has occured, look at the "
                          "/tmp/anaconda-tb* file(s) for more details")
                    # in the main thread, run exception handler
                    self._main_loop_handleException(dump_info)
            else:
                log.debug(
                    "In a non-main thread, sending a message with exception data"
                )
                # not in the main thread, just send message with exception
                # data and let message handler run the exception handler in
                # the main thread
                exc_info = dump_info.exc_info
                # new Simpleline package is now used in TUI. Look if Simpleline is
                # initialized or if this is some fallback from GTK or other stuff.
                if App.is_initialized():
                    # if Simpleline is initialized enqueue exception there
                    loop = App.get_event_loop()
                    loop.enqueue_signal(
                        ExceptionSignal(App.get_scheduler(),
                                        exception_info=exc_info))
                else:
                    hubQ.send_exception(
                        (exc_info.type, exc_info.value, exc_info.stack))
Ejemplo n.º 7
0
def gtk_batch_map(action, items, args=(), pre_func=None, batch_size=1):
    """
    Function that maps an action on items in a way that makes the action run in
    the main thread, but without blocking the main thread for a noticeable
    time. If a pre-processing function is given it is mapped on the items first
    before the action happens in the main thread.

    .. DANGER::
       MUST NOT BE CALLED NOR WAITED FOR FROM THE MAIN THREAD.

    :param action: any action that has to be done on the items in the main
                   thread
    :type action: (action_item, \\*args) -> None
    :param items: an iterable of items that the action should be mapped on
    :type items: iterable
    :param args: additional arguments passed to the action function
    :type args: tuple
    :param pre_func: a function that is mapped on the items before they are
                     passed to the action function
    :type pre_func: item -> action_item
    :param batch_size: how many items should be processed in one run in the main loop
    :raise AssertionError: if called from the main thread
    :return: None

    """

    assert(not threadMgr.in_main_thread())

    def preprocess(queue_instance):
        if pre_func:
            for item in items:
                queue_instance.put(pre_func(item))
        else:
            for item in items:
                queue_instance.put(item)

        queue_instance.put(TERMINATOR)

    def process_one_batch(arguments):
        (queue_instance, action, done_event) = arguments
        tstamp_start = time.time()
        tstamp = time.time()

        # process as many batches as user shouldn't notice
        while tstamp - tstamp_start < NOTICEABLE_FREEZE:
            for _i in range(batch_size):
                try:
                    action_item = queue_instance.get_nowait()
                    if action_item is TERMINATOR:
                        # all items processed, tell we are finished and return
                        done_event.set()
                        return False
                    else:
                        # run action on the item
                        action(action_item, *args)
                except queue.Empty:
                    # empty queue_instance, reschedule to run later
                    return True

            tstamp = time.time()

        # out of time but something left, reschedule to run again later
        return True

    item_queue_instance = queue.Queue()
    done_event = threading.Event()

    # we don't want to log the whole list, type and address is enough
    log.debug("Starting applying %s on %s", action, object.__repr__(items))

    # start a thread putting preprocessed items into the queue_instance
    threadMgr.add(AnacondaThread(prefix="AnaGtkBatchPre",
                                 target=preprocess,
                                 args=(item_queue_instance,)))

    run_in_loop(process_one_batch, (item_queue_instance, action, done_event))
    done_event.wait()
    log.debug("Finished applying %s on %s", action, object.__repr__(items))