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)
def tearDown(self): if basics.opt_print_statistics: statistics.EndTiming() statistics.PrintStatistics(self.include_analyzer)
_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 """