Ejemplo n.º 1
0
        def handle(self):
            """Using distcc protocol, read command and return include closure.

      Do the following:
       - Read from the socket, using the RPC protocol of distcc:
          - the current directory, and
          - the compilation command, already broken down into an argv vector.
       - Parse the command to find options like -I, -iquote,...
       - Invoke the include server's closure algorithm to yield a set of files
         and set of symbolic links --- both sets of files under client_root,
         which duplicates the part of the file system that CPP will need.
       - Transmit the file and link names on the socket using the RPC protocol.
      """
            statistics.StartTiming()
            currdir = distcc_pump_c_extensions.RCwd(self.rfile.fileno())
            cmd = distcc_pump_c_extensions.RArgv(self.rfile.fileno())

            try:
                try:
                    # We do timeout the include_analyzer using the crude mechanism of
                    # SIGALRM. This signal is problematic if raised while Python is doing
                    # I/O in the C extensions and during use of the subprocess
                    # module.
                    #
                    # TODO(klarlund) The Python library manual states: "When a signal
                    # arrives during an I/O operation, it is possible that the I/O
                    # operation raises an exception after the signal handler returns. This
                    # is dependent on the underlying Unix system's semantics regarding
                    # interrupted system calls."  We must clarify this. Currently, there
                    # is I/O during DoCompilationCommand:
                    #
                    #  - when a link is created in mirror_path.py
                    #  - module compress_files is used
                    #
                    # TODO(klarlund): Modify mirror_path so that is accumulates symbolic
                    # link operations instead of actually executing them on the spot. The
                    # accumulated operations can be executed after DoCompilationCommand
                    # when the timer has been cancelled.
                    include_analyzer.timer = basics.IncludeAnalyzerTimer()
                    files_and_links = (include_analyzer.DoCompilationCommand(
                        cmd, currdir, include_analyzer.client_root_keeper))
                finally:
                    # The timer should normally be cancelled during normal execution
                    # flow. Still, we want to make sure that this is indeed the case in
                    # all circumstances.
                    include_analyzer.timer.Cancel()

            except NotCoveredError as inst:
                # Warn user. The 'Preprocessing locally' message is meant to
                # assure the user that the build process is otherwise intact.
                fd = tempfile.TemporaryFile(mode='w+')
                print((
                    "Preprocessing locally. Include server not covering: %s for "
                    + "translation unit '%s'") %
                      ((inst.args and inst.args[0] or "unknown reason",
                        include_analyzer.translation_unit)),
                      file=fd,
                      end=' ')
                # We don't include a stack trace here.
                include_analyzer.email_sender.MaybeSendEmail(
                    fd, never=not inst.send_email)
                # The empty argv list denotes failure. Communicate this
                # information back to the distcc client, so that it can fall
                # back to preprocessing on the client.
                distcc_pump_c_extensions.XArgv(self.wfile.fileno(), [])
                if isinstance(inst, NotCoveredTimeOutError):
                    Debug(
                        DEBUG_TRACE,
                        "Clearing caches because of include server timeout.")
                    include_analyzer.ClearStatCaches()

            except SignalSIGTERM:
                # Normally, we will get this exception when the include server is no
                # longer needed. But we also handle it here, during the servicing of a
                # request. See basics.RaiseSignalSIGTERM.
                Debug(DEBUG_TRACE, "SIGTERM received while handling request.")
                raise
            except KeyboardInterrupt:
                # Propagate to the last-chance exception handler in Main.
                raise
            except SystemExit as inst:
                # When handler tries to exit (by invoking sys.exit, which in turn raises
                # SystemExit), something is really wrong. Terminate the include
                # server. But, print out an informative message first.
                fd = tempfile.TemporaryFile(mode='w+')
                print((
                    "Preprocessing locally. Include server fatal error: '%s' for "
                    + "translation unit '%s'") %
                      ((inst.args, include_analyzer.translation_unit)),
                      file=fd,
                      end=' ')
                _PrintStackTrace(fd)
                include_analyzer.email_sender.MaybeSendEmail(fd, force=True)
                distcc_pump_c_extensions.XArgv(self.wfile.fileno(), [])
                sys.exit("Now terminating include server.")
            # All other exceptions are trapped here.
            except Exception as inst:
                # Internal error. Better be safe than sorry: terminate include
                # server. But show error to user on stderr. We hope this message will be
                # reported.
                fd = tempfile.TemporaryFile(mode='w+')
                print((
                    "Preprocessing locally. Include server internal error: '%s: %s'"
                    + " for translation unit '%s'") %
                      ((inst.__class__, inst.args,
                        include_analyzer.translation_unit)),
                      file=fd)
                _PrintStackTrace(fd)
                # # Force this email through (if basics.opt_send_email is True), because
                # # this is the last one and this is an important case to report.
                include_analyzer.email_sender.MaybeSendEmail(fd, force=True)
                distcc_pump_c_extensions.XArgv(self.wfile.fileno(), [])
                raise SignalSIGTERM  # to be caught in Main with no further stack trace
            else:
                # No exception raised, include closure can be trusted.
                distcc_pump_c_extensions.XArgv(self.wfile.fileno(),
                                               files_and_links)
            # Print out observed paths.
            if basics.opt_path_observation_re:
                include_analyzer.build_stat_cache.WarnAboutPathObservations(
                    include_analyzer.translation_unit)
            # Finally, stop the clock and report statistics if needed.
            statistics.EndTiming()
            if basics.opt_statistics:
                statistics.PrintStatistics(include_analyzer)
Ejemplo n.º 2
0
 def tearDown(self):
     if basics.opt_print_statistics:
         statistics.EndTiming()
         statistics.PrintStatistics(self.include_analyzer)
Ejemplo n.º 3
0
                _PrintStackTrace(fd)
                # Force this email through (if basics.opt_send_email is True), because
                # this is the last one and this is an important case to report.
                include_analyzer.email_sender.MaybeSendEmail(fd, force=True)
                distcc_pump_c_extensions.XArgv(self.wfile.fileno(), [])
                raise SignalSIGTERM  # to be caught in Main with no further stack trace
            else:
                # No exception raised, include closure can be trusted.
                distcc_pump_c_extensions.XArgv(self.wfile.fileno(),
                                               files_and_links)
            # Print out observed paths.
            if basics.opt_path_observation_re:
                include_analyzer.build_stat_cache.WarnAboutPathObservations(
                    include_analyzer.translation_unit)
            # Finally, stop the clock and report statistics if needed.
            statistics.EndTiming()
            if basics.opt_statistics:
                statistics.PrintStatistics(include_analyzer)

    return IncludeHandler


def _ParseCommandLineOptions():
    """Parse arguments and options for the include server command.

  Returns:
    (include_server_port, pid_file), where include_server_port
    is a string and pid_file is a string or None 
  Modifies:
    option variables in module basics
  """