This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[cs] last c-only set of patches: gcc.c toplev.c


I checked in the attached patch to the compile-server.
The is is the last set of patches in the main directory
(I expect to check in the cp and objc patches this evening),
so in theory a bootstrap with --enable-languages=c should work.
However, my fast test machine is having hardware problems,
so there may well be some silly bugs I've introduced while
adding comments, ChangeLog entries and general clean-ups
before checking in.

So, you can check out the branch and play with it, but no
guarantees yet that anything works.  I plan to do testing
and hopefully get the basics working this weekend.
--
	--Per Bothner
per@bothner.com   http://per.bothner.com/


2003-08-15  Per Bothner  <pbothner@apple.com>

	* toplev.c (server_argv, server_argc):  New static variables.
	(server_loop):  Save options from 'F' command in server_argv
	and server_argc, after comparing with previously saved options.

	* gcc.c (write_switch_fds_request):  Use 'D' rather 'F' as command.
	* toplev.c (server_loop):  Fix conflicting use of 'F' command.

	* gcc.c (default_compilers):  Don't pass -fserver to @.cc1-server.
	(execute):  Pass command options to server as 'F' command.
	* toplev.c (server_get_command):  Recognize and ignore 'F' command.

2003-08-15  Mike Stump  <mrs@apple.com>

	* gcc.c:  Add stdin/stderr/stdout redirection, fixes -pipe.
	(send_fd, write_switch_fds_request):  New function.
	* toplev.c:  Add stdin/stderr/stdout redirection, fixes -pipe.
	(get_fd, push_to_fd, pop_fd):  New functions.
	* toplev.c:  Add umask support for server.
	
2003-08-15  Per Bothner  <pbothner@apple.com>

	* gcc.c (ENABLE_SERVER):  New macro.
	(struct infile, infile, n_infiles, input_file_compiler):  Move earlier.
	(use_server, kill_server, server_socket_name, server_socket):
	New variables.
	(cpp_unique_options, cc1_options, default_compilers):  Handle --server.
	(option_map):  New entries for --server and --kill-server.
	(delete_temp_fie):  Handle (poorly) kill_server.
	(execute):  If --server, pass command to server.
	(process_command):  Handle -server and --kill-server.
	(get_server_socket, write_input_request, write_output_request,
	write_input_requests):	New functions.
	* toplev.c (ENABLE_SERVER):  New macros.
	(server_mode, server_timeout):  New variable.
	(f_options):  Add server_mode.
	* toplev.c (server_get_command, server_loop):  New functions.
	(compile_file):  Split into compile_file_parse and compile_file_finish.
 	(process_options):  Move stuff to do_compile and lang_dependent_init.
	(do_compile):  Move backend_init call to lang_dependent_init.
	(finalize):  Re-set first_global_object_name and
	weak_global_object_name.
	(do_compile):  Loop over in_fnames.
	(toplev_main):  Call server_loop if requested.

Index: gcc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcc.c,v
retrieving revision 1.389.2.1
diff -u -p -r1.389.2.1 gcc.c
--- gcc.c	12 Aug 2003 23:06:58 -0000	1.389.2.1
+++ gcc.c	16 Aug 2003 00:47:39 -0000
@@ -84,6 +84,14 @@ compilation is specified by a string cal
 #include "gcc.h"
 #include "flags.h"
 
+#define ENABLE_SERVER 1
+
+#ifdef ENABLE_SERVER
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#endif
+
 #ifdef HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
 #endif
@@ -222,6 +230,23 @@ static int save_temps_flag;
 
 static int use_pipes;
 
+#ifdef ENABLE_SERVER
+static int use_server;
+static int kill_server;
+#endif
+
+struct infile
+{
+  const char *name;
+  const char *language;
+};
+
+/* Also a vector of input files specified.  */
+
+static struct infile *infiles;
+
+int n_infiles;
+
 /* The compiler version.  */
 
 static const char *compiler_version;
@@ -344,6 +369,15 @@ static int execute (void);
 static void alloc_args (void);
 static void clear_args (void);
 static void fatal_error (int);
+#ifdef ENABLE_SERVER
+static int server_socket = -1;
+static const char *server_socket_name = NULL;
+static int get_server_socket (const char *);
+static void write_input_request (const char *, int, int);
+static void write_input_requests (int);
+static void write_switch_fds_request (int);
+static void write_output_request (const char *, int);
+#endif
 #ifdef ENABLE_SHARED_LIBGCC
 static void init_gcc_specs (struct obstack *, const char *, const char *,
 			    const char *);
@@ -745,7 +779,7 @@ static const char *cpp_unique_options =
  %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\
  %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
  %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}}\
- %{trigraphs} %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\
+ %{trigraphs} %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %{!server:%i}\
  %{E|M|MM:%W{o*}}";
 
 /* This contains cpp options which are common with cc1_options and are passed
@@ -764,14 +798,14 @@ static const char *cpp_debug_options = "
 /* NB: This is shared amongst all front-ends.  */
 static const char *cc1_options =
 "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
- %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\
- -auxbase%{c|S:%{o*:-strip %*}%{!o*: %b}}%{!c:%{!S: %b}}\
+ %1 %{!Q:-quiet} %{!server:-dumpbase %B} %{d*} %{m*} %{a*}\
+ %{!server:-auxbase%{c|S:%{o*:-strip %*}%{!o*: %b}}%{!c:%{!S: %b}}}\
  %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi}\
  %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
  %{Qn:-fno-ident} %{--help:--help}\
- %{--target-help:--target-help}\
+ %{--target-help:--target-help} %{-param*}\
  %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
- %{fsyntax-only:-o %j} %{-param*}";
+ %{fsyntax-only:-o %j}";
 
 static const char *asm_options =
 "%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}";
@@ -909,7 +943,7 @@ static const struct compiler default_com
 		    cc1 -fpreprocessed %{save-temps:%b.i} %{!save-temps:%g.i} \
 			%(cc1_options)}\
 	  %{!save-temps:%{!traditional-cpp:%{!no-integrated-cpp:\
-		cc1 %(cpp_unique_options) %(cc1_options)}}}\
+		%{!server:cc1} %{server:@.cc1-server} %(cpp_unique_options) %(cc1_options)}}}\
         %{!fsyntax-only:%(invoke_as)}}}}", 0},
   {"-",
    "%{!E:%e-E required when input is from standard input}\
@@ -960,6 +994,9 @@ static const struct compiler default_com
 
 static const int n_default_compilers = ARRAY_SIZE (default_compilers) - 1;
 
+/* The compiler used to process the current input file.  */
+static struct compiler *input_file_compiler;
+
 /* A vector of options to give to the linker.
    These options are accumulated by %x,
    and substituted into the linker command with %X.  */
@@ -1029,6 +1066,7 @@ static const struct option_map option_ma
    {"--include-with-prefix", "-iwithprefix", "a"},
    {"--include-with-prefix-before", "-iwithprefixbefore", "a"},
    {"--include-with-prefix-after", "-iwithprefix", "a"},
+   {"--kill-server", "-kill-server", 0},
    {"--language", "-x", "a"},
    {"--library-directory", "-L", "a"},
    {"--machine", "-m", "aj"},
@@ -1062,6 +1100,7 @@ static const struct option_map option_ma
    {"--quiet", "-q", 0},
    {"--resource", "-fcompile-resource=", "aj"},
    {"--save-temps", "-save-temps", 0},
+   {"--server", "-server", 0},
    {"--shared", "-shared", 0},
    {"--silent", "-q", 0},
    {"--specs", "-specs=", "aj"},
@@ -2247,6 +2286,18 @@ delete_temp_files (void)
   for (temp = always_delete_queue; temp; temp = temp->next)
     delete_if_ordinary (temp->name);
   always_delete_queue = 0;
+
+#ifdef ENABLE_SERVER
+  if (kill_server)
+    {
+      static char kill_request[5] = "T'0'\n";
+      get_server_socket (".cc1-server"); /* FIXME */
+      if (write (server_socket, kill_request, 5) != 5)
+	pfatal_with_name ("(socket write)");
+    }
+  if (server_socket >= 0)
+    close (server_socket);
+#endif
 }
 
 /* Delete all the files to be deleted on error.  */
@@ -2607,6 +2658,7 @@ execute (void)
   int i;
   int n_commands;		/* # of command.  */
   char *string;
+  int ret_code = 0;
   struct command
   {
     const char *prog;		/* program name.  */
@@ -2743,6 +2795,82 @@ execute (void)
       char *errmsg_fmt, *errmsg_arg;
       const char *string = commands[i].argv[0];
 
+#ifdef ENABLE_SERVER
+      if (use_server && string[0] == '@' && string[1] == '.')
+	{
+	  int sock = get_server_socket (string + 1);
+	  char buf[1024];
+	  int has_o;
+	  int argc;
+	  int n_read;
+	  int rcode = 0;
+	  void *base;
+	  int wlen;
+
+	  for (argc = 0; commands[i].argv[argc] != NULL; argc++) ;
+	  has_o = argc > 2 &&  strcmp (commands[i].argv[argc-2], "-o") == 0;
+	  fprintf (stderr, "before writing to socket!\n");
+	  write_switch_fds_request (sock);
+
+	  { /* Send flags to server. */
+	    int j;
+	    obstack_1grow (&obstack, 'F');
+	    for (j = 1;  j < argc - 2 * has_o;  j++)
+	      {
+		char *arg = commands[i].argv[j];
+		obstack_1grow (&obstack, '\000');
+		obstack_grow (&obstack, arg, strlen (arg) + 1);
+	      }
+	    obstack_1grow (&obstack, '\n');
+	    base = obstack_base (&obstack);
+	    wlen = obstack_object_size (&obstack);
+	    if (write (sock, base, wlen) != wlen)
+	      pfatal_with_name ("(socket write)");
+	    obstack_free (&obstack, base);
+	  }
+
+	  write_input_requests (sock);
+	  if (has_o)
+	    write_output_request (commands[i].argv[argc-1], sock);
+	  else
+	    write_output_request ("", sock);
+	  for (;;)
+	    {
+	      int j;
+	      n_read = read (sock, buf, sizeof(buf));
+	      if (n_read <= 0)
+		break; /* FIXME */
+	      for (j = 0;  j < n_read;  j++)
+		{
+		  char c = buf[j];
+		  if (c == 1)
+		    {
+		      j++;
+		      if (j == n_read)
+			{
+			  n_read = read (sock, buf, 1);
+			  j = 0;
+			}
+		      rcode = buf[j];
+		      goto close_socket;
+		    }
+		  putc (c, stderr);
+		}
+	    }
+	close_socket:
+	  /*close (sock);*/
+	  fprintf (stderr, "server's return code: %d\n", rcode);
+	  if (rcode >= MIN_FATAL_STATUS)
+	    {
+	      if (rcode > greatest_status)
+		greatest_status = rcode;
+	      ret_code = -1;
+	    }
+	  commands[i].pid = -1;
+	}
+      else
+#endif
+	{
       /* For some bizarre reason, the second argument of execvp() is
 	 char *const *, not const char *const *.  */
       commands[i].pid = pexecute (string, (char *const *) commands[i].argv,
@@ -2759,6 +2887,7 @@ execute (void)
 
       if (string != commands[i].prog)
 	free ((void *) string);
+	}
     }
 
   execution_count++;
@@ -2770,7 +2899,6 @@ execute (void)
      since they can be spawned by the process that exec'ed us.  */
 
   {
-    int ret_code = 0;
 #ifdef HAVE_GETRUSAGE
     struct timeval d;
     double ut = 0.0, st = 0.0;
@@ -2780,9 +2908,17 @@ execute (void)
       {
 	int j;
 	int status;
-	int pid;
+	int pid = commands[i].pid;;
+
+#ifdef ENABLE_SERVER
+	if (pid == -1)
+	  {
+	    i++;
+	    continue;
+	  }
+#endif
 
-	pid = pwait (commands[i].pid, &status, 0);
+	pid = pwait (pid, &status, 0);
 	if (pid < 0)
 	  abort ();
 
@@ -2882,18 +3018,6 @@ static struct switchstr *switches;
 
 static int n_switches;
 
-struct infile
-{
-  const char *name;
-  const char *language;
-};
-
-/* Also a vector of input files specified.  */
-
-static struct infile *infiles;
-
-int n_infiles;
-
 /* True if multiple input files are being compiled to a single
    assembly file.  */
 
@@ -3085,8 +3209,8 @@ process_command (int argc, const char *c
   char *temp1;
   const char *spec_lang = 0;
   int last_language_n_infiles;
-  int have_c = 0;
-  int have_o = 0;
+  int have_c;
+  int have_o;
   int lang_n_infiles = 0;
 #ifdef MODIFY_TARGET_NAME
   int is_modify_target_name;
@@ -3525,6 +3649,18 @@ warranty; not even for MERCHANTABILITY o
 	  use_pipes = 1;
 	  n_switches++;
 	}
+#ifdef ENABLE_SERVER
+      else if (strcmp (argv[i], "-server") == 0)
+	{
+	  use_server = 1;
+	  n_switches++;
+	}
+      else if (strcmp (argv[i], "-kill-server") == 0)
+	{
+	  kill_server = 1;
+	  n_switches++;
+	}
+#endif
       else if (strcmp (argv[i], "-###") == 0)
 	{
 	  /* This is similar to -v except that there is no execution
@@ -3831,7 +3967,7 @@ warranty; not even for MERCHANTABILITY o
   n_infiles = 0;
   last_language_n_infiles = -1;
 
-  /* This, time, copy the text of each switch and store a pointer
+  /* This time, copy the text of each switch and store a pointer
      to the copy in the vector of switches.
      Store all the infiles in their vector.  */
 
@@ -3871,6 +4007,8 @@ warranty; not even for MERCHANTABILITY o
 	;
       else if (! strcmp (argv[i], "-ftarget-help"))
 	;
+      else if (! strcmp (argv[i], "-fkill-server"))
+	switches[n_switches++].validated = 1;
       else if (! strcmp (argv[i], "-fhelp"))
 	;
       else if (argv[i][0] == '+' && argv[i][1] == 'e')
@@ -4033,6 +4171,7 @@ warranty; not even for MERCHANTABILITY o
 	}
     }
 
+
   if (n_infiles == last_language_n_infiles && spec_lang != 0)
     error ("warning: `-x %s' after last input file has no effect", spec_lang);
 
@@ -4147,9 +4286,6 @@ static const char *input_suffix;
 static struct stat input_stat;
 static int input_stat_set;
 
-/* The compiler used to process the current input file.  */
-static struct compiler *input_file_compiler;
-
 /* These are variables used within do_spec and do_spec_1.  */
 
 /* Nonzero if an arg has been started and not yet terminated
@@ -5654,6 +5790,135 @@ process_brace_body (const char *p, const
 
   return p;
 }
+
+#ifdef ENABLE_SERVER
+static int
+get_server_socket (const char *socket_name)
+{
+  struct sockaddr_un server;
+  if (server_socket >= 0
+      && server_socket_name != NULL
+      && strcmp (server_socket_name, socket_name) != 0)
+    {
+      free ((PTR) server_socket_name);
+      server_socket_name = NULL;
+      close (server_socket);
+      server_socket = -1;
+    }
+  if (server_socket < 0)
+    {
+      server_socket = socket (AF_UNIX, SOCK_STREAM, 0);
+      if (server_socket < 0)
+	fatal ("can't create socket");
+      server.sun_family = AF_UNIX;
+      fprintf (stderr, "created socket: %d path:%s max:%d\n", server_socket,
+	      socket_name, (int) sizeof(server.sun_path));
+      sprintf (server.sun_path, "%.*s", (int) sizeof (server.sun_path)-1,
+	      socket_name);
+      server_socket_name = xstrdup (socket_name);
+
+      if (connect (server_socket, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0)
+	{
+#if 0
+	  ... try starting server ...;
+#endif
+	  close (server_socket);
+	  perror ("connecting stream socket");
+	  exit (1);
+	}
+    }
+  return server_socket;
+}
+
+static void
+write_input_request (const char *filename, int filename_length, int fd)
+{
+  int wlen;
+  void *base;
+  obstack_grow (&obstack, "I\000", 2);
+  obstack_grow (&obstack, filename, filename_length);
+  obstack_grow (&obstack, "\000\n", 2);
+  base = obstack_base (&obstack);
+  wlen = obstack_object_size (&obstack);
+  if (write (fd, base, wlen) != wlen)
+    pfatal_with_name ("(socket write)");
+  obstack_free (&obstack, base);
+}
+
+static void
+write_output_request (const char *filename, int fd)
+{
+  int filename_length = strlen (filename);
+  int wlen;
+  void *base;
+  obstack_grow (&obstack, "O\000", 2);
+  obstack_grow (&obstack, filename, filename_length);
+  obstack_grow (&obstack, "\000\n", 2);
+  base = obstack_base (&obstack);
+  wlen = obstack_object_size (&obstack);
+  if (write (fd, base, wlen) != wlen)
+    pfatal_with_name ("(socket write)");
+  obstack_free (&obstack, base);
+}
+
+static void
+write_input_requests (int sock)
+{
+  if (combine_inputs)
+    {
+      int j;
+      for (j = 0; (int) j < n_infiles; j++)
+	write_input_request (infiles[j].name,
+			     strlen (infiles[j].name),
+			     sock);
+    }
+  else
+    {
+      write_input_request (input_filename, input_filename_length, sock);
+    }
+}
+
+static void
+send_fd (int fd, int sock)
+{
+  struct msghdr msg;
+  char controlmsg[CMSG_SPACE(sizeof (fd))];
+  struct cmsghdr *cmsg;
+  struct iovec vec;
+  char *str = "x";
+  
+  msg.msg_name = 0;
+  msg.msg_namelen = 0;
+  vec.iov_base = str;
+  vec.iov_len = 1;
+  msg.msg_iov = &vec;
+  msg.msg_iovlen = 1;
+  msg.msg_control = controlmsg;
+  msg.msg_controllen = sizeof (controlmsg);
+  cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN(sizeof (fd));
+  *(int*)CMSG_DATA(cmsg) = fd;
+  msg.msg_controllen = cmsg->cmsg_len;
+  msg.msg_flags = 0;
+
+  if (sendmsg (sock, &msg, 0) == -1)
+    abort ();
+}
+
+static void
+write_switch_fds_request (int sock)
+{
+  static char req[2] = "D\n";
+  if (write (sock, req, 2) != 2)
+    pfatal_with_name ("(socket write)");
+  send_fd (0, sock);
+  send_fd (1, sock);
+  send_fd (2, sock);
+}
+#endif
+
 
 /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
    on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.813.2.3
diff -u -p -r1.813.2.3 toplev.c
--- toplev.c	14 Aug 2003 21:02:07 -0000	1.813.2.3
+++ toplev.c	16 Aug 2003 00:47:39 -0000
@@ -79,6 +79,23 @@ Software Foundation, 59 Temple Place - S
 #include "opts.h"
 #include "coverage.h"
 
+#define ENABLE_SERVER 1
+#define USE_SELECT 1
+
+#ifdef USE_POLL
+#include <sys/poll.h>
+#endif
+#ifdef USE_SELECT
+#include <sys/time.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#ifdef ENABLE_SERVER
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#endif
+
 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
 #endif
@@ -113,9 +130,13 @@ static int lang_dependent_init (const ch
 static void init_asm_output (const char *);
 static void finalize (void);
 
+static int server_get_command (int, char**, int*, int*, int*);
+static void server_loop (void);
+
 static void crash_signal (int) ATTRIBUTE_NORETURN;
 static void setup_core_dumping (void);
-static void compile_file (void);
+static void compile_file_parse (void);
+static void compile_file_finish (void);
 
 static int print_single_switch (FILE *, int, int, const char *,
 				const char *, const char *,
@@ -176,6 +197,9 @@ const char *progname;
 /* Copy of argument vector to toplev_main.  */
 static const char **save_argv;
 
+/* -1: compile single file; 0: compile multiple files; 1: server. */
+int server_mode = -1;
+
 /* Name of top-level original source file (what was input to cpp).
    This comes from the #-command at the beginning of the actual input.
    If there isn't any there, then this is the cc1 input file name.  */
@@ -1006,6 +1030,7 @@ static const param_info lang_independent
 
 static const lang_independent_options f_options[] =
 {
+  {"server", &server_mode, 2 },
   {"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1 },
   {"eliminate-unused-debug-symbols", &flag_debug_only_used_symbols, 1 },
   {"eliminate-unused-debug-types", &flag_eliminate_unused_debug_types, 1 },
@@ -1713,13 +1738,13 @@ pop_srcloc (void)
   input_file_stack_tick++;
 }
 
-/* Compile an entire translation unit.  Write a file of assembly
-   output and various debugging dumps.  */
+/* Compile an entire translation unit.  Write a file of assembly output
+   and various debugging dumps.  Called once for each translation unit.  */
 
 static void
-compile_file (void)
-{
-  /* Initialize yet another pass.  */
+compile_file_parse (void)
+{ 
+ /* Initialize yet another pass.  */
 
   init_final (main_input_filename);
   coverage_init (aux_base_name);
@@ -1737,7 +1762,14 @@ compile_file (void)
   /* Compilation is now finished except for writing
      what's left of the symbol table output.  */
   timevar_pop (TV_PARSE);
+}
+
+/* After processing an entire translation unit, finish the compilation.
+   Only called once for each output file, even for many input files.  */
 
+static void
+compile_file_finish ()
+{
   if (flag_syntax_only)
     return;
 
@@ -4030,31 +4062,11 @@ general_init (const char *argv0)
 static void
 process_options (void)
 {
-  /* Allow the front end to perform consistency checks and do further
-     initialization based on the command line options.  This hook also
-     sets the original filename if appropriate (e.g. foo.i -> foo.c)
-     so we can correctly initialize debug output.  */
-  no_backend = (*lang_hooks.post_options) (&main_input_filename);
-  input_filename = main_input_filename;
-
 #ifdef OVERRIDE_OPTIONS
   /* Some machines may reject certain combinations of options.  */
   OVERRIDE_OPTIONS;
 #endif
 
-  /* Set aux_base_name if not already set.  */
-  if (aux_base_name)
-    ;
-  else if (main_input_filename)
-    {
-      char *name = xstrdup (lbasename (main_input_filename));
-
-      strip_off_ending (name, strlen (name));
-      aux_base_name = name;
-    }
-  else
-    aux_base_name = "gccaux";
-
   /* Set up the align_*_log variables, defaulting them to 1 if they
      were still unset.  */
   if (align_loops <= 0) align_loops = 1;
@@ -4272,6 +4284,19 @@ backend_init (void)
 static int
 lang_dependent_init (const char *name)
 {
+  /* Set aux_base_name if not already set.  */
+  if (aux_base_name)
+    ;
+  else if (dump_base_name)
+    {
+      char *aname = xstrdup (dump_base_name);
+      
+      strip_off_ending (aname, strlen (aname));
+      aux_base_name = aname;
+    }
+  else
+    aux_base_name = "gccaux";
+
   if (dump_base_name == 0)
     dump_base_name = name ? name : "gccdump";
 
@@ -4279,6 +4304,9 @@ lang_dependent_init (const char *name)
   if ((*lang_hooks.init_eachsrc) () == 0)
     return 0;
 
+  /* Set up the back-end if requested.  */
+  backend_init ();
+
   init_asm_output (name);
 
   /* These create various _DECL nodes, so need to be called after the
@@ -4365,6 +4393,18 @@ finalize (void)
 
   /* Language-specific end of compilation actions.  */
   (*lang_hooks.finish) ();
+
+  if (first_global_object_name != NULL)
+    {
+      free ((void *) first_global_object_name);
+      first_global_object_name = NULL;
+    }
+
+  if (weak_global_object_name != NULL)
+    {
+      free ((void *) weak_global_object_name);
+      weak_global_object_name = NULL;
+    }
 }
 
 /* Initialize the compiler.  */
@@ -4374,6 +4414,9 @@ init_compile_once (void)
   /* The bulk of the command line switch processing.  */
   process_options ();
 
+  if (server_mode < 0 && num_in_fnames > 1)
+    server_mode = 0;
+
   init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL
 		  || debug_info_level == DINFO_LEVEL_VERBOSE
 #ifdef VMS_DEBUGGING_INFO
@@ -4386,49 +4429,388 @@ init_compile_once (void)
   (*lang_hooks.init_once) ();
 }
 
-/* Initialize the compiler, and compile the input file.  */
+/* Do most of the (post-initialization) compilation, if not in server mode. */
 static void
 do_compile (void)
 {
+  unsigned i;
+
   /* Initialize timing first.  The C front ends read the main file in
      the post_options hook, and C++ does file timings.  */
   if (time_report || !quiet_flag  || flag_detailed_statistics)
     timevar_init ();
   timevar_start (TV_TOTAL);
 
-  /* Don't do any more if an error has already occurred.  */
-  if (!errorcount)
+  lang_dependent_init (in_fnames[0]);
+  for (i = 0;  i < num_in_fnames;  i++)
     {
-      /* Set up the back-end if requested.  */
-      if (!no_backend)
-	backend_init ();
+      const char *filename = in_fnames[i];
+      main_input_filename = input_filename = filename;
+
+      if (flag_unit_at_a_time)
+	{
+	  open_dump_file (DFI_cgraph, NULL);
+	  cgraph_dump_file = rtl_dump_file;
+	  rtl_dump_file = NULL;
+	}
+
+      no_backend = (*lang_hooks.post_options) (&filename);
+
+      if (! no_backend)
+	{
+	  if (i > 0)
+	    (*lang_hooks.init_eachsrc) ();
+	  compile_file_parse ();
+	}
+      if (flag_unit_at_a_time)
+	{
+	  rtl_dump_file = cgraph_dump_file;
+	  cgraph_dump_file = NULL;
+	  close_dump_file (DFI_cgraph, NULL, NULL_RTX);
+	}
+    }
+  if (! no_backend)
+    compile_file_finish ();
+  finalize ();
 
-      /* Language-dependent initialization.  Returns true on success.  */
-      if (lang_dependent_init (main_input_filename))
+  /* Stop timing and print the times.  */
+  timevar_stop (TV_TOTAL);
+  timevar_print (stderr);
+}
+
+/* Read a single server command from FD.
+   Each server command starts with a command letter.
+   Next is an arbitrary char interpreted as the quote delimiter
+   for the current command. (For human-readable command input or debugging,
+   use '"' or '\''; for production use '\0' is recommended.)
+   The command ends with the first CR or LF which is not within quotes.
+   (*BUFP) is used as an input buffer, which may be reallocated if needed.
+   (*BLENP) is the allocated length of (*BUFP).
+   (*LIMP) is the index just past the last valid byte in (*BUFP).
+   (*POSP) is where to start reading the next line.
+   Returns the first char (the command letter) or -1 on end of file or timeout.
+   On successful return, the command letter is in (*BUFP)[0],
+   and the ending CR or LF is in (*BUFP)[*POSP-1].  */
+static int
+server_get_command (int fd, char **bufp, int *posp, int *limp, int *blenp)
+{
+  int quote = 0;
+  int in_quote = 0;
+  int pos = *posp;
+  int blen = *blenp;
+  int limit = *limp;
+  char *buf = *bufp;
+ again:
+  if (pos > 0)
+    {
+      memmove (buf, buf + pos, limit - pos);
+      limit -= pos;
+      pos = 0;
+    }
+  for (;;)
+    {
+      char ch;
+      if (pos >= limit)
 	{
-	  if (flag_unit_at_a_time)
+	  ssize_t count;
+	  int avail = blen - limit;
+	  if (avail < 100)
+	    {
+	      blen = 2 * blen;
+	      buf = xrealloc (buf, blen);
+	      *bufp = buf;
+	      *blenp = blen;
+	      avail = blen - limit;
+	    }
+	  count = read (fd, buf + pos, avail);
+	  if (count <= 0)
 	    {
-	      open_dump_file (DFI_cgraph, NULL);
-	      cgraph_dump_file = rtl_dump_file;
-	      rtl_dump_file = NULL;
+	      if (pos > 0)
+		fatal_error ("unexpected end-of-file in server command input");
+	      return -1;
 	    }
+	  limit += count;
+	}
+      ch = buf[pos++];
+      if ((ch == '\r' || ch == '\n') && ! in_quote)
+	{
+	  if (pos == 1)
+	    goto again;
+	  *posp = pos;
+	  *limp = limit;
+	  return buf[0] & 0xff;
+	}
+      if (pos == 2)
+	quote = ch;
+      if (ch == quote)
+	in_quote = 1 - in_quote;
+    }
+}
+
+static int
+get_fd (int sock)
+{
+  struct msghdr msg;
+  struct iovec iov;
+  char buf[1];
+  int rv;
+  char controlmsg[CMSG_SPACE(sizeof (int))];
+  struct cmsghdr *cmsg;
+
+  iov.iov_base = buf;
+  iov.iov_len = 1;
+  msg.msg_name = 0;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = controlmsg;
+  msg.msg_controllen = sizeof (controlmsg);
+    
+  rv = recvmsg (sock, &msg, 0);
+  if (rv == -1) {
+    perror ("recvmsg");
+    return -1;
+  }
+
+  cmsg = CMSG_FIRSTHDR(&msg);
+  if (!cmsg->cmsg_type == SCM_RIGHTS) {
+    /* fprintf (stderr, "bad type for control message: %d\n", cmsg->cmsg_type); */
+    return -1;
+  }
+  return *(int*)CMSG_DATA(cmsg);
+} 
+
+static int old_fd[3] = { -1, -1, -1 };
+
+static void
+push_to_fd (int fd0, int fd1, int fd2)
+{
+  if (old_fd[0] != -1)
+    abort ();
+  old_fd[0] = dup (0);
+  old_fd[1] = dup (1);
+  old_fd[2] = dup (2);
+  close (0);
+  close (1);
+  close (2);
+  dup2 (fd0, 0);
+  dup2 (fd1, 1);
+  dup2 (fd2, 2);
+}
+
+static void
+pop_fd (void)
+{
+  if (old_fd[0] == -1)
+    abort ();
+  close (0);
+  close (1);
+  close (2);
+  dup2 (old_fd[0], 0);
+  dup2 (old_fd[1], 1);
+  dup2 (old_fd[2], 2);
+  close (old_fd[0]);
+  close (old_fd[1]);
+  close (old_fd[2]);
+  old_fd[0] = -1;
+  old_fd[1] = -1;
+  old_fd[2] = -1;
+}
+
+/* How long server should  wait for request, in milliseconds. */
+
+static long server_timeout;
+
+/* The options passed by the gcc client when we're in server mode. */
+static char** server_argv;
+
+/* The number of elements of server_argv. */
+static int server_argc;
 
-	  compile_file ();
+/* Main "event loop" when in compile server mode.
+   Read a server command and process it. */
 
-	  if (flag_unit_at_a_time)
+static void
+server_loop ()
+{
+  int blen = 200;
+  char *command_buffer = xmalloc (blen);
+  int fd = 0;
+  int pos = 0;
+  int limit = 0;
+  int command;
+  int omask;
+#ifdef ENABLE_SERVER
+  struct sockaddr_un server;
+  int sock = socket (AF_UNIX, SOCK_STREAM, 0);
+
+  if (sock < 0)
+    fatal_error ("can't create server socket: %m");
+  server.sun_family = AF_UNIX;
+  sprintf (server.sun_path, "./.%s-server", progname);
+
+  /* We tighten down the compile server to the current user.  */
+  omask = umask (0077);
+  /* FIXME - remove for production, testing is easier if we don't do this. */
+  /* unlink (server.sun_path); */
+  if (bind (sock, (struct sockaddr *) &server, sizeof (struct sockaddr_un))) 
+    {
+      /* This is a second invocation of a compiler server, we don't need two.  */
+      if (errno == EADDRINUSE)
+	{
+	  close (sock);
+	  return;
+	}
+	
+      fatal_error ("can't bind server socket %s: %m", server.sun_path);
+    }
+  listen (sock, 5);
+  umask (omask);
+  fd = -1;
+#endif /* ENABLE_SERVER */
+  for (;;)
+    {
+#ifdef ENABLE_SERVER
+      if (fd < 0)
+	{
+	  fd = accept (sock, 0, 0);
+	  if (fd < 0)
+	    fatal_error("can't connect to client socket: %m");
+	}
+#endif /* ENABLE_SERVER */
+      /* dup2 (fd, 2); */
+      command = server_get_command (fd, &command_buffer, &pos, &limit, &blen);
+      if (command < 0)
+	{
+#ifdef ENABLE_SERVER
+	  close (fd);
+	  fd = -1;
+	  continue;
+#else /* ! ENABLE_SERVER */
+	  break;
+#endif /* ! ENABLE_SERVER */
+	}
+
+      /*fprintf (stderr, "command '%c', '%.*s'\n", command, pos-2, command_buffer+1);*/
+      if (command == 'O') /* "output" */
+	{
+	  int i;
+	  char xbuf[100];
+	  int asm_name_length = pos - 4;
+	  char *abuf = xmalloc (asm_name_length+1);
+	  char *fname = command_buffer + 2;
+	  fname [asm_name_length] = 0;
+	  memcpy (abuf, fname, asm_name_length+1);
+	  asm_file_name = abuf;
+	  if (! quiet_flag)
+	    fprintf (stderr, "Assembler file: '%s'\n", asm_file_name);
+
+	  do_compile ();
+
+	  for (i = num_in_fnames;  --i >= 0; )
 	    {
-	      rtl_dump_file = cgraph_dump_file;
-	      cgraph_dump_file = NULL;
-              close_dump_file (DFI_cgraph, NULL, NULL_RTX);
+	      const char *name = in_fnames[i];
+	      free ((void*) name);
+	      in_fnames[i] = NULL;
 	    }
+	  in_fnames = NULL;
+	  num_in_fnames = 0;
+	  sprintf (xbuf, "(done compiling)\n");
+	  write (fd, xbuf, strlen (xbuf));
+	  xbuf[0] = 1;
+	  xbuf[1] = (errorcount || sorrycount ? FATAL_EXIT_CODE
+		     : SUCCESS_EXIT_CODE);
+	  write (fd, xbuf, 2);
+	  if (old_fd[0] != -1)
+	    pop_fd ();
+	}
+      else if (command == 'I') /* "input" */
+	{
+	  const char *filename;
+	  command_buffer[pos-2] = 0;
+	  filename = xstrdup (command_buffer + 2);
+	  fprintf (stderr, "Source file: '%s'\n", filename);
+	  add_input_filename (filename);
 	}
+      else if (command == 'F') /* flags */
+	{
+	  int quote = command_buffer[1];
+	  int nargs = 0;
+	  int matches_old_flags;
+	  int i;
+	  char *start;
+	  matches_old_flags = server_argv != NULL;
 
-      finalize ();
+	  start = command_buffer + 2;;
+	  for (i = 2;  i < pos - 1;  i++)
+	    {
+	      if (command_buffer[i] == quote)
+		{
+		  command_buffer[i] = '\0';  /* In case quote != '\0'. */
+		  if (start != NULL)
+		    { /* End of argument */
+		      if (nargs >= server_argc
+			  ||  strcmp (server_argv[nargs], start) != 0)
+			matches_old_flags = 0;
+		      nargs++;
+		      start = NULL;
+		    }
+		  else
+		    start = command_buffer + i + 1;
+		}
+	    }
+	  if (! matches_old_flags)
+	    {
+	      char ** argv = xmalloc (nargs * sizeof (char*));
+	      int iarg = 0;
+	      start = command_buffer + 2;
+	      for (i = 2;  i < pos - 1;  i++)
+		{
+		  if (command_buffer[i] == '\0')
+		    {
+		      if (start != NULL)
+			{
+			  argv[iarg++] = xstrdup (start);
+			  start = NULL;
+			}
+		      else
+			start = command_buffer + i + 1;
+		    }
+		}
+	      if (server_argv != NULL)
+		free (server_argv);
+	      server_argv = argv;
+	      server_argc = nargs;
+#if 0
+	      for (iarg = 0;  iarg < server_argc;  iarg++)
+		fprintf (stderr, "Flag: '%s'\n", server_argv[iarg]);
+#endif
+	    }
+	}
+      else if (command == 'T')
+	{
+	  char *num = command_buffer + 1;
+	  char first = *num;
+	  if (first < '0' || first > '9')  num++;
+	  server_timeout = atol (num);
+	  if (server_timeout == 0)
+	    break;
+	  warning ("non-zero server timeout not implemented");
+	}
+      else if (command == 'D')
+	{
+	  int fd0 = get_fd (fd);
+	  int fd1 = get_fd (fd);
+	  int fd2 = get_fd (fd);
+	  push_to_fd (fd0, fd1, fd2);
+	}
+      else
+	fatal_error ("server received uncognized command");
     }
-
-  /* Stop timing and print the times.  */
-  timevar_stop (TV_TOTAL);
-  timevar_print (stderr);
+#ifdef ENABLE_SERVER
+  close (sock);
+  unlink (server.sun_path);
+#endif
 }
 
 /* Entry point of cc1, cc1plus, jc1, f771, etc.
@@ -4458,7 +4840,12 @@ toplev_main (unsigned int argc, const ch
 
       /* If an error has already occurred, give up.  */
       if (! errorcount)
-	do_compile ();
+	{
+	  if (server_mode > 0)
+	    server_loop ();
+	  else
+	    do_compile ();
+	}
     }
 
   if (errorcount || sorrycount)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]