[incremental] Patch: FYI: start multiple servers

Tom Tromey tromey@redhat.com
Thu Apr 17 18:56:00 GMT 2008


I'm checking this in on the incremental-compiler branch.

This patch changes gcc so that multiple compile servers can be run at
the same time.  This is done by giving a '-j' option to 'gcc --server'.

This is not as cool as multi-threading the server, but it is a lot
simpler to implement and should perform decently.

Tom

gcc/ChangeLog:
2008-04-17  Tom Tromey  <tromey@redhat.com>

	* server.h (server_start, server_main_loop): Update.
	* server.c (server_directory): Update comment.
	(get_socket_name): Always set server_directory.
	(forget_socket_name): Free server_directory.
	(server_cleanup): Don't remove socket or directory.
	(delete_server_socket): New function.
	(server_start): Add 'nservers' argument.  Pass -j to new process.
	(server_main_loop): Add 'nservers' argument.
	(client_kill_server): Loop to kill all servers.  Call
	delete_server_socket.
	* toplev.c (toplev_main): Handle -j.
	* gcc.c (server_count): New global.
	(process_command): Handle -j.
	(main): Use server_count.

Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 133758)
+++ gcc/gcc.c	(working copy)
@@ -200,6 +200,11 @@
 
 static int server;
 
+/* The number of server processes to start.  Only meaningful if
+   'server' is set.  */
+
+static int server_count = 1;
+
 /* Flag indicating that we should kill a running server process.  */
 
 static int kill_server;
@@ -3903,6 +3908,21 @@
 	      }
 	      break;
 
+	    case 'j':
+	      {
+		char *arg;
+		if (p[1] != 0)
+		  arg = &p[1];
+		else if (i + 1 < argc)
+		  arg = argv[++i];
+		else
+		  error ("argument to '-j' is missing");
+		server_count = atoi (arg);
+		if (server_count <= 0)
+		  error ("argument to '-j' must be positive");
+	      }
+	      break;
+
 	    case 'v':	/* Print our subcommands and print versions.  */
 	      n_switches++;
 	      /* If they do anything other than exactly `-v', don't set
@@ -4236,6 +4256,13 @@
 		last_language_n_infiles = n_infiles;
 	      continue;
 	    }
+	  else if (c == 'j')
+	    {
+	      /* Don't pass the -j option down.  */
+	      if (p[1] == 0)
+		++i;
+	      continue;
+	    }
 	  switches[n_switches].part1 = p;
 	  /* Deal with option arguments in separate argv elements.  */
 	  if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
@@ -6551,7 +6578,8 @@
   if (server)
     {
       /* FIXME: allow more than cc1... */
-      server_start (find_a_file (&exec_prefixes, "cc1", X_OK, 0));
+      server_start (find_a_file (&exec_prefixes, "cc1", X_OK, 0),
+		    server_count);
       return 0;
     }
 
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 133644)
+++ gcc/toplev.c	(working copy)
@@ -2608,11 +2608,16 @@
   /* Initialization of GCC's environment, and diagnostics.  */
   general_init (argv[0]);
 
-  if (argc == 2 && !strncmp (argv[1], "-fserver=", 9))
+  if (argc >= 2 && !strncmp (argv[1], "-fserver=", 9))
     {
       int fd = atoi (argv[1] + 9);
+      int jopt = 1;
+
+      if (argc >= 3 && !strncmp (argv[2], "-j", 2))
+	jopt = atoi (argv[2] + 2);
+
       server_mode = true;
-      return server_main_loop (argv[0], fd);
+      return server_main_loop (argv[0], fd, jopt);
     }
 
   /* Parse the options and do minimal processing; basically just
Index: gcc/server.c
===================================================================
--- gcc/server.c	(revision 133644)
+++ gcc/server.c	(working copy)
@@ -50,8 +50,8 @@
 /* The name of the server socket we're using.  */
 static char *server_socket_name;
 
-/* The name of the server directory.  Only set in the server.  We
-   delete this when the server exits.  */
+/* The name of the server directory.  We delete this when the server
+   exits.  */
 static char *server_directory;
 
 /* The file descriptor of our connection to the server.  */
@@ -96,8 +96,8 @@
 	      error ("could not make directory %s: %s", dir, xstrerror (errno));
 	      exit (FATAL_EXIT_CODE);
 	    }
-	  server_directory = xstrdup (dir);
 	}
+      server_directory = xstrdup (dir);
 
       server_socket_name = reconcat (dir, dir, "/", basename, "-server", NULL);
     }
@@ -114,6 +114,11 @@
       free (server_socket_name);
       server_socket_name = NULL;
     }
+  if (server_directory)
+    {
+      free (server_directory);
+      server_directory = NULL;
+    }
 }
 
 /* If SOCKET is not -1, close the server socket.  Unlink the server
@@ -122,7 +127,15 @@
 server_cleanup (int socket)
 {
   if (socket != -1)
-    close (socket);
+    {
+      close (socket);
+      socket = -1;
+    }
+}
+
+static void
+delete_server_socket (void)
+{
   if (server_socket_name)
     unlink (server_socket_name);
   if (server_directory)
@@ -130,10 +143,11 @@
 }
 
 /* Start a compile server.  PROGRAM is the full path name of the
-   server to start.  Returns when the server is ready, or prints a
-   message to stderr and exits on failure.  */
+   server to start.  NSERVERS is the number of server processes to
+   start.  Returns when the server is ready, or prints a message to
+   stderr and exits on failure.  */
 void
-server_start (char *program)
+server_start (char *program, int nservers)
 {
   int fds[2];
 
@@ -150,6 +164,7 @@
       {
 	/* Child.  */
 	char fdstr[40];
+	char jstr[20];
 	char *args[5];
 	int i = 0;
 #ifdef ENABLE_VALGRIND_CHECKING
@@ -159,6 +174,8 @@
 	args[i++] = program;
 	sprintf (fdstr, "-fserver=%d", fds[1]);
 	args[i++] = fdstr;
+	sprintf (jstr, "-j%d", nservers);
+	args[i++] = jstr;
 	args[i++] = NULL;
 	/* Close read end of notification pipe.  */
 	close (fds[0]);
@@ -361,9 +378,10 @@
    it, accepting requests and acting on them.  PROGNAME is the full
    path to the server executable.  FD is the completion file
    descriptor, used to notify the gcc driver when the server is ready
-   to accept connections.  */
+   to accept connections.  NSERVERS is the number of server processes
+   to start.  */
 int
-server_main_loop (const char *progname, int fd)
+server_main_loop (const char *progname, int fd, int nservers)
 {
   int sockfd = open_socket (progname);
   char reply = 't';
@@ -391,6 +409,17 @@
 
   listen (sockfd, 5);
 
+  /* Create the requested server processes.  */
+  while (--nservers > 0)
+    {
+      pid_t subserver;
+      /* It is ok if a fork fails; it just means we have fewer servers
+	 than requested.  */
+      subserver = fork ();
+      if (subserver == 0 || subserver == -1)
+	break;
+    }
+
   while (result)
     {
       int reqfd = accept (sockfd, NULL, 0);
@@ -646,12 +675,30 @@
 void
 client_kill_server (const char *progname)
 {
-  if (!client_connect (progname))
+  bool report_error = true;
+  while (true)
     {
-      error ("couldn't connect to server: %s", xstrerror (errno));
-      return;
+      if (!client_connect (progname))
+	{
+	  /* Report an error if the first connection attempt fails.
+	     Any subsequent failure is normal -- it means we've killed
+	     all the running servers.  */
+	  if (report_error)
+	    {
+	      error ("couldn't connect to server: %s", xstrerror (errno));
+	      break;
+	    }
+	  else
+	    {
+	      /* Can't find another server, so clean up.  */
+	      delete_server_socket ();
+	      break;
+	    }
+	}
+
+      send_command_and_wait ('K');
+      report_error = false;
     }
-  send_command_and_wait ('K');
 }
 
 /* Assert that either this compiler is running standalone, or that the
Index: gcc/server.h
===================================================================
--- gcc/server.h	(revision 132956)
+++ gcc/server.h	(working copy)
@@ -21,8 +21,8 @@
 #define GCC_SERVER_H
 
 /* Functions for the server to use.  */
-extern void server_start (char *);
-extern int server_main_loop (const char *progname, int);
+extern void server_start (char *, int);
+extern int server_main_loop (const char *progname, int, int);
 extern bool server_start_back_end (bool *);
 extern bool server_interrupted_p (void);
 



More information about the Gcc-patches mailing list