dkumar      02/08/31 04:00:32

  Modified:    gcc      Tag: server-branch gcc.c toplev.c
               libiberty Tag: server-branch pexecute.c
  Log:
  Initial commit of server prototype
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.129.8.1 +26 -7     gcc3/gcc/gcc.c
  
  Index: gcc.c
  ===================================================================
  RCS file: /cvs/Darwin/gcc3/gcc/gcc.c,v
  retrieving revision 1.129
  retrieving revision 1.129.8.1
  diff -u -r1.129 -r1.129.8.1
  --- gcc.c     2002/06/26 22:36:47     1.129
  +++ gcc.c     2002/08/31 11:00:29     1.129.8.1
  @@ -3006,6 +3006,11 @@
        n_commands++;
         }
   
  +  /* APPLE LOCAL begin compilation server */
  +  /* We do this since the compile server isn't supported when -pipe is not present, 
due to synchronization issues */
  +  /* Zem - I haven't verified that this check works, but it should */
  +  /*  if (n_commands <= 1) unsetenv("USE_COMPILE_SERVER"); */
  +  /* APPLE LOCAL end */
     argbuf[argbuf_index] = 0;
   
     /* If -v, print what we are about to do, and maybe query.  */
  @@ -3091,7 +3096,6 @@
                                   | (string == commands[i].prog
                                      ? PEXECUTE_SEARCH : 0)
                                   | (verbose_flag ? PEXECUTE_VERBOSE : 0)));
  -
         if (commands[i].pid == -1)
        pfatal_pexecute (errmsg_fmt, errmsg_arg);
   
  @@ -3132,10 +3136,25 @@
             continue;
          }
         /* APPLE LOCAL end 2920964 */
  -     pid = pwait (commands[i].pid, &status, 0);
  -     if (pid < 0)
  -       abort ();
  -
  +      /* APPLE LOCAL begin compilation server */
  +     /* pexecute() returns the special pid -42 if a server connection was 
successful; we no longer wait on the process in that case */
  +     /* If necessary, we could have the server send back the pid of the child 
process it forked, and wait on that */
  +     if ( commands[i].pid != -42)
  +       {
  +         /* APPLE LOCAL end */
  +         pid = pwait (commands[i].pid, &status, 0);
  +         if (pid < 0)
  +           abort ();
  +         /* APPLE LOCAL begin compilation server */
  +       }
  +     else
  +       {
  +         pid = -42;
  +         status = 0;
  +         /* Perhaps fold any errors into here as well */
  +         ret_code = 0;
  +       }
  +      /* APPLE LOCAL end */
   #ifdef HAVE_GETRUSAGE
        if (report_times)
          {
  @@ -3698,13 +3717,13 @@
          if (is_cpp_driver)
            add_preprocessor_option ("--help", 6);
             /* APPLE LOCAL begin 2920964 */
  -       #if 0
  +#if 0
          /* Our assembler and linkder do not support --help.  */
             /* APPLE LOCAL end 2920964 */
          add_assembler_option ("--help", 6);
          add_linker_option ("--help", 6);
             /* APPLE LOCAL begin 2920964 */
  -       #endif
  +#endif
             /* APPLE LOCAL end 2920964 */
        }
         else if (strcmp (argv[i], "-ftarget-help") == 0)
  
  
  
  1.140.4.1 +468 -13   gcc3/gcc/toplev.c
  
  Index: toplev.c
  ===================================================================
  RCS file: /cvs/Darwin/gcc3/gcc/toplev.c,v
  retrieving revision 1.140
  retrieving revision 1.140.4.1
  diff -u -r1.140 -r1.140.4.1
  --- toplev.c  2002/07/18 00:48:05     1.140
  +++ toplev.c  2002/08/31 11:00:30     1.140.4.1
  @@ -109,7 +109,7 @@
   extern tree last_assemble_variable_decl;
   
   static void general_init PARAMS ((char *));
  -static void parse_options_and_default_flags PARAMS ((int, char **));
  +static void parse_options_and_default_flags PARAMS ((int*, char ***));
   static void do_compile PARAMS ((void));
   static void process_options PARAMS ((void));
   static void lang_independent_init PARAMS ((void));
  @@ -346,6 +346,11 @@
   int flag_debug_only_used_symbols = 1;
   #endif
   
  +/* APPLE LOCAL begin Radar 2940311 Emit N_PARAMS stab */
  +/* Nonzero if the N_PARAMS stab is to be generated */
  +int flag_emit_params_stab = 1;
  +/* APPLE LOCAL end*/
  +
   /* Nonzero means do optimizations.  -O.
      Particular numeric values stand for particular amounts of optimization;
      thus, -O2 stores 2 here.  However, the optimizations beyond the basic
  @@ -1583,6 +1588,28 @@
   int no_pound_warnings = 0;
   /* APPLE LOCAL end -Wno-#warnings  Radar 2796309 ilr */
   
  +/* APPLE LOCAL begin compilation server */
  +#include <sys/types.h>
  +#include <sys/socket.h>
  +#include <sys/un.h>
  +#include <unistd.h>
  +#include <sys/uio.h>
  +
  +int flag_pfe_in_memory = 0;
  +enum pfe_action last_pfe_operation = PFE_NOT_INITIALIZED;
  +char *last_pfe_arch = (char *) "";
  +char *last_pfe_file = (char *) "";
  +#define MAX_WAITERS 5
  +
  +int flag_socket_created = 0;
  +int flag_first_compilation = 0;
  +int number_of_children = 0;
  +int conn = -1;
  +int lastconn = -1;
  +int max_children = 1;
  +char argbuf[8192];
  +/* APPLE LOCAL end */
  +
   /* Likewise for -W.  */
   
   static const lang_independent_options W_options[] =
  @@ -4980,15 +5007,19 @@
     }
   #endif /* RLIMIT_STACK defined */
   }
  +int pfe_in_memory_p()
  +{
  +  return flag_pfe_in_memory;
  +}
   
   /* Parse command line options and set default flag values, called
      after language-independent option-independent initialization.  Do
      minimal options processing.  Outputting diagnostics is OK, but GC
      and identifier hashtables etc. are not initialized yet.  */
   static void
  -parse_options_and_default_flags (argc, argv)
  -     int argc;
  -     char **argv;
  +parse_options_and_default_flags (pargc, pargv)
  +     int *pargc;
  +     char ***pargv;
   {
     int i;
   /* APPLE LOCAL PFE */
  @@ -4996,11 +5027,10 @@
     int flag_pfe_validate = 0;
     char *arch = (char *) "unkn";
   #endif
  -  
  -  /* Save in case md file wants to emit args as a comment.  */
  -  save_argc = argc;
  -  save_argv = argv;
  -
  +  /* APPLE LOCAL begin compilation server */  
  +  int argc = *pargc;
  +  char **argv = *pargv;
  +  /* APPLE LOCAL end */
     /* Initialize register usage now so switches may override.  */
     init_reg_sets ();
   
  @@ -5018,6 +5048,30 @@
     (*lang_hooks.init_options) ();
   #endif
   
  +  /* APPLE LOCAL begin compile server */
  +  if (getenv("USE_COMPILE_SERVER"))
  +    {
  +      /* pfe_in_memory_p() should return true if this succeeds */
  +      /* Also consider moving the other language initialization stuff, and
  +      maybe init_ggc() from do_compile() to here */
  +      /* Also note that the pfe file is arch specific: so we have to check the 
architecture specified to see if it matches the one in memory, and perhaps fork off a 
new copy from either main() or have the new copy unmap the current pfe and load the 
new one */
  +
  +      /* Scan argv for pfe_load: if it's a load, load it and then fork */
  +      /* This should also set last_pfe_file, last_pfe_arch etc. */
  +       if (0 == check_and_load_pfe(argc, argv))
  +         {
  +           fprintf(stderr, "PFE load success\n");
  +           flag_pfe_in_memory = 1;
  +           if (0 != create_server_and_wait(pargc, pargv))
  +             {
  +               flag_pfe_in_memory = 0;
  +             }
  +           argc = *pargc;
  +           argv = *pargv;
  +         }
  +       /* If it's not a load, send back msg to driver indicating that server did 
not activate Hmm at the first compile there's no comm channel to the driver! So just 
don't make a server until you get a pfe load operation */
  +    }
  +  /* APPLE LOCAL end */
     /* Scan to see what optimization level has been specified.  That will
        determine the default value of many flags.  */
     for (i = 1; i < argc; i++)
  @@ -5026,6 +5080,9 @@
         /* We also need to know whether we're doing -fload or -fdump BEFORE we
         allocate any memory.  This scan for -Oxx serves as a convenient
         place to check for that too.  */
  +      /* APPLE LOCAL begin compile server */
  +      if (!pfe_in_memory_p())
  +     /* APPLE LOCAL end */
         if (errorcount == 0)
           {
          if (strncmp (argv[i], "-fload=", 7) == 0)
  @@ -5055,7 +5112,7 @@
          else if (strcmp (argv[i], "-fno-validate") == 0)
            flag_pfe_validate = 0;
        }
  -      
  +     
         if (strcmp (argv[i], "-ftime-report") == 0)
           time_report = 1;
         else if (strcmp (argv[i], "-quiet") == 0)
  @@ -5091,6 +5148,9 @@
        }
       }
   
  +  /* APPLE LOCAL begin compile server */
  +  if (!pfe_in_memory_p())
  +    /* APPLE LOCAL end */
   /* APPLE LOCAL begin PFE dpatel */
   #ifdef PFE
      /* Turn on macro validation during pfe load */
  @@ -5126,7 +5186,10 @@
           time_report = 1;
         init_timevar ();
         timevar_start (TV_TOTAL);
  -      pfe_load_compiler_state (pfe_file);
  +      /* APPLE LOCAL begin compile server */
  +      if (!pfe_in_memory_p())
  +     /* APPLE LOCAL end */
  +     pfe_load_compiler_state (pfe_file);
       }
     
     /* Perform language-specific options initialization.  */
  @@ -5207,6 +5270,11 @@
     flag_unwind_tables = IA64_UNWIND_INFO;
   #endif
   
  +
  +  /* Save in case md file wants to emit args as a comment.  */
  +  save_argc = argc;
  +  save_argv = argv;
  +
   #ifdef OPTIMIZATION_OPTIONS
     /* Allow default optimizations to be specified on a per-machine basis.  */
     OPTIMIZATION_OPTIONS (optimize, optimize_size);
  @@ -5743,7 +5811,6 @@
   #ifdef PFE
     }
   #endif
  -
     /* Language-independent initialization.  Also sets up GC, identifier
        hashes etc.  */
     lang_independent_init ();
  @@ -5782,6 +5849,394 @@
   #endif
   }
   
  +/* APPLE LOCAL begin compile server */
  +int create_server_socket(const char *name)
  +{
  +  int server_fd, sock_len;
  +  struct sockaddr_un server_socket;
  +  if ((server_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  +    {
  +      perror("socket");
  +      return (-1);
  +    }
  +  /* The unlink will fail if we don't have the same privileges as the original 
server process that created the socket..must deal with that error eventually */
  +  unlink(name);
  +  memset(&server_socket, 0, sizeof(server_socket));
  +  server_socket.sun_family = AF_UNIX;
  +  strcpy(server_socket.sun_path, name);
  +  /* All this is very BSD specific, make it more portable */
  +#ifdef SCM_RIGHTS
  +  sock_len = sizeof(server_socket.sun_family) + strlen(server_socket.sun_path) \
  +    + sizeof(server_socket.sun_len) +  1;
  +  server_socket.sun_len = sock_len;
  +#else
  +  sock_len = strlen(server_socket.sunpath) + sizeof(server_socket.sun_family);
  +#endif
  +
  +  if (bind(server_fd, (struct sockaddr *) &server_socket, sock_len) < 0)
  +    {
  +      perror("bind() in create_server_socket");
  +      return (-2);
  +    }
  +  return (server_fd);
  +}
  +/* Signal handler which handles SIGCHLDs, and decrements the number of outstanding 
compiles - this number can be compared against a dynamically computed number of 
maximum supported parallel compiles, to determine if we should service an incoming 
compilation request, or have it block */
  +void wait_for_children()
  +{
  +  int wstatus;
  +
  +  while(wait3(&wstatus,WNOHANG,NULL) > 0)
  +    {
  +      number_of_children--;
  +      /* lastconn is present as a first step; it can very easily be clobbered, and 
we'll end up sending the GA to the wrong driver. We need to have a growable array of 
waiting requests, and wait_for_children() should send a go ahead to the request that 
has been waiting the longest */
  +      if ((lastconn != -1) && (number_of_children < max_children))
  +        {
  +          if ( write(lastconn, "GA", 3) < 0)
  +            perror("write() in wait_for_children()");
  +          close(lastconn);
  +          lastconn = -1;
  +     }
  +    }
  +}
  +
  +int recv_fd (int clifd)
  +{
  +  int newfd = -1, status = -1, nread;
  +  char *ptr;
  +  char buf[2];
  +  struct iovec iov[1];
  +  struct msghdr msg;
  +
  +  static struct cmsghdr *cmptr = NULL;
  +#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
  +  
  +  for (; ;)
  +    {
  +      iov[0].iov_base = buf;
  +      iov[0].iov_len = sizeof(buf);
  +      msg.msg_iov = iov;
  +      msg.msg_iovlen = 1;
  +      msg.msg_name = NULL;
  +      msg.msg_namelen = 0;
  +      if (cmptr == NULL && (cmptr = xmalloc(CONTROLLEN)) == NULL)
  +     return (-1);
  +      
  +      msg.msg_control = (caddr_t) cmptr;
  +      msg.msg_controllen = CONTROLLEN;
  +
  +      if ( (nread = recvmsg(clifd, &msg, 0)) < 0)
  +     {
  +       perror("recvmsg() failed in read_fd()");
  +       return(-1); /* Might want to remove this later */
  +     }
  +      else
  +     if ( 0 == nread)
  +       {
  +         perror("recvmsg() returned 0 in read_fd");
  +         return (-1);
  +       }
  +      /*      fprintf(stderr, "nread in recv_fd was %d\n", nread);  */
  +
  +      for (ptr = buf; ptr < &buf[nread]; )
  +     {
  +       if (0 == *ptr++)
  +         {
  +           if (ptr != &buf[nread-1])
  +             fprintf(stderr, "Message format error\n");
  +           status = *ptr & 255;
  +           if (!status)
  +             {
  +               if (msg.msg_controllen != CONTROLLEN)
  +                 fprintf(stderr, "status == 0 but no fd\n");
  +               newfd = *(int *) CMSG_DATA(cmptr);
  +             }
  +           else
  +             newfd = -status;
  +           nread -= 2;
  +         }
  +     }
  +      if (status >= 0)
  +     return (newfd);
  +    }
  +}
  +
  +int accept_connection(int s)
  +{ 
  +  struct sockaddr_un sock_addr; 
  +  int sock_len;
  +  int t;
  +  
  +  sock_len = sizeof(struct sockaddr_un);
  +
  +  if ((t = accept(s, (struct sockaddr *) &sock_addr,&sock_len) ) < 0)
  +    return(-1);
  +
  +  return(t);
  +}
  +
  +int create_server_and_wait (int *pargc, char ***pargv)
  +{
  +  int argc = *pargc;
  +  char ** argv = *pargv;
  +  char path[128];
  +  char *ptr;
  +  char *nc;
  +  int server_fd = -1, nbytes, argpos;
  +  pid_t pid;
  +  int workaround_fd;
  +  
  +  if (!flag_socket_created)
  +    {
  +      ptr = argv[0] + strlen (argv[0]);
  +      while ( (ptr != argv[0]) && '/' != *ptr) ptr--;
  +
  +      if (ptr != argv[0]) ptr++;
  +      /* Ideally the path to the server would be unambiguous; one way to 
disambiguate the socket name would be to add the compiler version string, and the name 
of the current user, resulting in a path like /tmp/.cc1_1200_root_socket, so a driver 
wouldn't connect to a server of the wrong version, or belonging to a different user */
  +      sprintf(path, "/tmp/.%ssocket", ptr);
  +      if ( (server_fd = create_server_socket(path)) < 0)
  +     {
  +       fprintf(stderr, "Could not create server socket\n");
  +       return (-1);
  +     }
  +      flag_socket_created = 1;
  +      flag_first_compilation = 1;
  +      /* MAX_CHILDREN can be set in the environment to let the server know that 
only x children should be allowed to exist at any given point..none of this works yet 
*/
  +      if ((nc = getenv("MAX_CHILDREN")) != NULL)
  +     {
  +       max_children = atoi(nc);
  +       if ( (max_children < 1) || (max_children > 11))
  +         max_children = 1;
  +     }
  +    }
  +  /* Install wait_for_children as the SIGCHLD handler */
  +  signal(SIGCHLD, wait_for_children);
  +  /* signal(SIGPIPE, SIG_IGN); */
  +  if (flag_first_compilation)
  +    {
  +      if ( (pid = fork()) < 0)
  +     {
  +       perror("fork");
  +       close(server_fd);
  +       return (-1);
  +     }
  +      else
  +     if (pid)
  +       {
  +         return 0;
  +       }
  +       /* We now daemonize the process */
  +      close (STDIN_FILENO);
  +      close (STDOUT_FILENO);
  +      close (STDERR_FILENO);
  +      /* (void) setsid(); */
  +      flag_first_compilation = 0;
  +      /* This workaround is needed for 3008249 */
  +      workaround_fd = open("/dev/null", O_RDWR, 0);
  +      dup2(workaround_fd, STDIN_FILENO);
  +      dup2(workaround_fd, STDOUT_FILENO);
  +      dup2(workaround_fd, STDERR_FILENO);
  +    }
  +  
  +  /* perhaps use select with a timeout here - this way, we could have the server 
exit if it hasn't been used in a while */
  +  /* We may also want to listen to multiple descriptors here, say one for the 
header descriptor cache, the other for compilation requests; or we could just have a 
real protocol with different packet codes for each request */
  +  
  +  if (listen(server_fd, MAX_WAITERS) < 0)
  +    {
  +      perror("listen() in main()");
  +      return (-1);
  +    }
  +  
  +  for (;;) 
  +    {
  +      /* Perhaps select() here and unlink() socket & exit if timeout */
  +      if ((conn = accept_connection(server_fd)) < 0) 
  +     {
  +       if (EINTR == errno) 
  +         continue;         
  +       perror("accept");   
  +       return (-1);
  +     }
  +      /* Right now, we fork() immediately on a connection; we may want to determine 
if we have resources to support another compilation here, rather than later (by 
comparing against the current number of children etc. ) */
  +      if ( (pid = fork()) < 0)
  +     {
  +       perror("fork");
  +       close(conn);
  +       close(server_fd);
  +       return (-1);
  +     }
  +      else
  +     if (pid)
  +       {
  +         /* The outstanding compiles checks don't work right now, since the driver 
ends up waiting on "as" etc. anyway, so it doesn't spin off a new process. Possible 
solutions: have the driver not wait on as, which screws up ld. Or have the user invoke 
make with -j 10 or some absurdly high number, and have the server regulate 
compilation, by waiting to send GA sequences to the driver until ready. Our model 
still has the server forking after every connection..perhaps we shouldn't fork until 
we determine if we have the resources to do so. Another idea: to have the driver write 
back to the process we just forked when it receives the GA, and have the fork proceed 
only then..or perhaps replace that with a pipe from the parent..*/
  +         number_of_children++;
  +         if (number_of_children <= max_children)
  +           {
  +             write(conn, "GA", 3);
  +             close(conn);
  +             conn = -1;
  +           }
  +         else
  +           {
  +             lastconn = conn;
  +           }
  +         /* Add conn to a waiter's list here, rather than just hoping the signal 
handler sends the GA to the right waiter */
  +         /*          close (conn); */
  +         continue;
  +       }
  +     else
  +       if (0 == pid)
  +         {
  +           /* We're in the child, receive file descriptors and dup2 them 
appropriately */
  +           int stdin_fd = -1;
  +           int stdout_fd = -1;
  +           int stderr_fd = -1;
  +           if ( (stdin_fd = recv_fd(conn)) != STDIN_FILENO)
  +             {
  +               if (dup2(stdin_fd, STDIN_FILENO) != STDIN_FILENO)
  +                 perror("dup2() error to STDIN");
  +             }
  +           
  +           if ( (stdout_fd = recv_fd(conn)) != STDOUT_FILENO)
  +             {
  +               if (dup2(stdout_fd, STDOUT_FILENO) != STDOUT_FILENO)
  +                 perror("dup2() error to STDOUT");
  +             }
  +           if ( (stderr_fd = recv_fd(conn)) != STDERR_FILENO)
  +             {
  +               if (dup2(stderr_fd, STDERR_FILENO) != STDERR_FILENO)
  +                 perror("dup2() error to STDERR");
  +             }
  +           /* while (stderr_fd != -1); */ /* This can be handy since gdb's 
follow-fork-mode doesn't work at the moment */
  +           /* We use a fixed size buffer to read in the args, both wasteful and 
unsafe. Should receive size as part of the protocol, but that's for a later release */
  +           if ( (nbytes = read (conn, argbuf, 8192)) < 0)
  +             {
  +               perror("read() in main()");
  +               fprintf(stderr, "read() in main(), errno was %d\n", errno);
  +               return (-1);
  +             }
  +           else
  +             {
  +               char **new_argv;
  +               int new_argc;
  +               
  +               /*fprintf(stderr, "argbuf read was %s\n", argbuf);*/
  +               fflush(stderr);
  +               /* allocate for 512 arguments at most; this should also be part of 
the protocol, and done dynamically */
  +               new_argv = xmalloc (512 * sizeof (char *));
  +               new_argv[0] = argbuf;
  +               new_argc = 1;
  +               for (argpos = 0; argpos < nbytes; argpos++)
  +                 {
  +                   if ('\0' == argbuf[argpos])
  +                     {
  +                       if (argbuf[argpos + 1] == '\0') /* We've reached the last 
argument */
  +                         break;
  +                       new_argv[new_argc] = &(argbuf[argpos+1]);
  +                       new_argc++;
  +                     }
  +                 }
  +               *pargc = new_argc;
  +               *pargv = new_argv;
  +               /* Check the pfe argument, and if it is a valid pfe, send a proceed 
("PG") code to the driver */
  +               if (check_pfe_args_and_arch(new_argc, new_argv))
  +                 {
  +                   write (conn, "PG", 3);
  +                   /* fprintf(stderr, "Sending PG to driver \n"); */
  +                   /* close(conn); */
  +                 }
  +               else 
  +                 {
  +                   /* Unfortunately this code path is somehow exercised wrongly on 
rare occasions, have to determine why. It seems as though packets sometimes get 
dropped even though we have a reliable SOCK_STREAM socket. Perhaps it's Yet Another 
Kernel Bug */
  +                   write (conn, "NG", 3);
  +                   fprintf(stderr, "Sending NG to driver \n");
  +                   close(conn);
  +                   exit(0); /* Hmm parent is still alive at this point, should make 
parent exit too perhaps via a crude kill(getppid())? */
  +                 }
  +               return 0;
  +             }
  +         }
  +    }
  +  return -1;
  +}
  +
  +int check_and_load_pfe (int argc, char ** argv)
  +{
  +  int i;
  +  char *arch = (char *) "unkn";
  +  int flag_pfe_validate = 0;
  +  if (pfe_in_memory_p()) fprintf(stderr, "PFE already in memory!\n");
  +  
  +  /* This is essentially a cut&paste from the pfe argument checks */
  +  for (i = 1; i < argc; i++)
  +    {
  +#ifdef PFE
  +      if (!pfe_in_memory_p())
  +      if (errorcount == 0)
  +        {
  +       if (strncmp (argv[i], "-fload=", 7) == 0)
  +         {
  +           if (pfe_operation == PFE_LOAD)
  +             error ("Only one -fload allowed");
  +           else if (pfe_operation == PFE_DUMP)
  +             error ("Cannot specify both -fload and -fdump - which is it?");
  +           else
  +             {
  +               last_pfe_file = xstrdup (&argv[i][7]);
  +               pfe_open_pfe_file (&argv[i][7], arch, 0);
  +             }
  +         }
  +       else if (strncmp (argv[i], "-fdump=", 7) == 0)
  +         {
  +           return -1;
  +         }
  +       else if (strcmp (argv[i], "-farch=ppc") == 0)
  +         arch = (char *) "ppc";
  +       else if (strcmp (argv[i], "-farch=i386") == 0)
  +         arch = (char *) "i386";
  +       else if (strcmp (argv[i], "-fvalidate") == 0)
  +         flag_pfe_validate = 1;
  +       else if (strcmp (argv[i], "-fno-validate") == 0)
  +         flag_pfe_validate = 0;
  +     }
  +    }
  +  if (pfe_operation != PFE_LOAD) return -1;
  +  init_timevar ();
  +  timevar_start (TV_TOTAL); /* the TV_TOTAL timevar init should be moved elsewhere 
*/
  +  if (!pfe_in_memory_p())
  +    pfe_load_compiler_state (pfe_file);
  +  last_pfe_arch = xstrdup (arch);
  +  fprintf(stderr, "last_pfe_arch and last_pfe_file are %s and %s\n", last_pfe_arch, 
last_pfe_file);
  +  pfe_macro_validation = flag_pfe_validate;
  +  return 0;
  +#endif
  +}
  +
  +int check_pfe_args_and_arch (int argc, char **argv)
  +{
  +  int i;
  +  char *current_pfe_arch = (char *) "", *current_pfe_file = (char *) "";
  +  /*   if (getenv("BREAK_ON_CHECK")) 
  +       while (i!=-1); */
  +  for (i = 1; i < argc; i++)
  +    {
  +#ifdef PFE
  +      if (strncmp (argv[i], "-fload=", 7) == 0)
  +     {
  +       current_pfe_file = &argv[i][7];
  +     }
  +      else if (strcmp (argv[i], "-farch=ppc") == 0)
  +     current_pfe_arch = (char *) "ppc";
  +      else if (strcmp (argv[i], "-farch=i386") == 0)
  +     current_pfe_arch = (char *) "i386";
  +    }
  +  if (!strcmp(current_pfe_file, last_pfe_file) && !strcmp(current_pfe_arch, 
last_pfe_arch))
  +    return 1;
  +  else
  +    return 0;
  +#endif
  +}
  +/* APPLE LOCAL end compile server */
  +
   /* Entry point of cc1, cc1plus, jc1, f771, etc.
      Decode command args, then call compile_file.
      Exit code is FATAL_EXIT_CODE if can't open files or if there were
  @@ -5801,7 +6256,7 @@
   
     /* Parse the options and do minimal processing; basically just
        enough to default flags appropriately.  */
  -  parse_options_and_default_flags (argc, argv);
  +  parse_options_and_default_flags (&argc, &argv);
   
     /* Exit early if we can (e.g. -help).  */
     if (!exit_after_options)
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.3.14.1  +213 -12   gcc3/libiberty/pexecute.c
  
  Index: pexecute.c
  ===================================================================
  RCS file: /cvs/Darwin/gcc3/libiberty/pexecute.c,v
  retrieving revision 1.3
  retrieving revision 1.3.14.1
  diff -u -r1.3 -r1.3.14.1
  --- pexecute.c        2001/10/23 03:49:01     1.3
  +++ pexecute.c        2002/08/31 11:00:31     1.3.14.1
  @@ -48,6 +48,14 @@
   #include "libiberty.h"
   #include "safe-ctype.h"
   
  +/* APPLE LOCAL begin compilation server */
  +/* All of these should be autoconf conditionalized at some point */
  +#include <sys/types.h>
  +#include <sys/socket.h>
  +#include <sys/uio.h>
  +#include <sys/un.h>
  +/* APPLE LOCAL end */
  +
   /* stdin file number.  */
   #define STDIN_FILE_NO 0
   
  @@ -418,8 +426,8 @@
         close (output_desc);
       }
   
  -  pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
  -    (_P_NOWAIT, program, fix_argv(argv));
  +      pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
  +     (_P_NOWAIT, program, fix_argv(argv));
   
     if (input_desc != STDIN_FILE_NO)
       {
  @@ -664,6 +672,58 @@
   #if ! defined (__MSDOS__) && ! defined (OS2) && ! defined (MPW) \
       && ! (defined (_WIN32) && ! defined (_UWIN))
   
  +/* APPLE LOCAL begin compilation server */
  +int send_fd (int clifd, int fd)
  +{
  +  struct iovec iov[1];
  +  struct msghdr msg;
  +  static struct cmsghdr *cmptr = NULL;
  +#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
  +  char buf[2];
  +
  +  int nbytes;
  +  
  +  iov[0].iov_base = buf;
  +  iov[0].iov_len = 2;
  +  msg.msg_iov = iov;
  +  msg.msg_iovlen = 1;
  +  msg.msg_name = NULL;
  +  msg.msg_namelen = 0;
  +
  +  if (fd < 0) 
  +    {
  +      msg.msg_control = NULL;
  +      msg.msg_controllen = 0;
  +      buf[1] = -fd;
  +      if (0==buf[1])
  +     buf[1] = 1;
  +    }
  +  else
  +    {
  +      if (cmptr == NULL && (cmptr =  xmalloc(CONTROLLEN)) == NULL)
  +     {
  +       perror("malloc() in send_fd()");
  +       return (-1);
  +     }
  +      
  +      cmptr->cmsg_level = SOL_SOCKET;
  +      cmptr->cmsg_type = SCM_RIGHTS;
  +      cmptr->cmsg_len = CONTROLLEN;
  +      msg.msg_control = (caddr_t) cmptr;
  +      msg.msg_controllen = CONTROLLEN;
  +      *(int *) CMSG_DATA(cmptr) = fd;
  +      buf[1]= 0;
  +    }
  +  buf[0] = 0;
  +  if ( (nbytes = sendmsg(clifd, &msg, 0))  != 2)
  +    {
  +      perror("sendmsg: nbytes wasn't 2");
  +      return (-1);
  +    }
  +  return (0);
  +}
  +/* APPLE LOCAL end */
  +
   extern int execv ();
   extern int execvp ();
   
  @@ -686,6 +746,10 @@
        (i.e. the next command is the first of a group).  */
     static int last_pipe_input;
   
  +  /* APPLE LOCAL begin compilation server */
  +  int flag_using_server = 0;
  +  /* APPLE LOCAL end */
  +
     /* If this is the first process, initialize.  */
     if (flags & PEXECUTE_FIRST)
       last_pipe_input = STDIN_FILE_NO;
  @@ -712,18 +776,155 @@
         last_pipe_input = STDIN_FILE_NO;
       }
   
  -  /* Fork a subprocess; wait and retry if it fails.  */
  -  sleep_interval = 1;
  -  pid = -1;
  -  for (retries = 0; retries < 4; retries++)
  -    {
  -      pid = fork ();
  -      if (pid >= 0)
  -     break;
  -      sleep (sleep_interval);
  -      sleep_interval *= 2;
  +  /*APPLE LOCAL begin compilation server */
  +  /* Code to check env var, perhaps conditionalized on some option */
  +  if ( getenv("USE_COMPILE_SERVER"))
  +    {
  +      char *ptr;
  +      ptr = argv[0] + strlen (argv[0]);
  +      while ( (ptr != argv[0]) && ptr[0] != '/') ptr--;
  +      if (ptr != argv[0]) ptr++;
  +      if ( 0 == strncmp(ptr, "cc1", 3))
  +     {
  +       int driver_fd, sock_len;
  +       struct sockaddr_un driver_socket;
  +       int argpos;
  +       char sockname[128];
  +       char ga[3];
  +       /* We may want to move to a less ambiguous socket path, such as 
/tmp/.cc1_1200_root_socket */
  +       sprintf(sockname, "/tmp/.%ssocket", ptr);
  +       fflush(stdout);
  +       fflush(stderr);
  +       flag_using_server = 0;
  +       
  +       if ((driver_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  +         {
  +           perror("socket");
  +           return (-1);
  +         }
  +       
  +       memset (&driver_socket, 0 , sizeof(driver_socket));
  +       driver_socket.sun_family = AF_UNIX;
  +       strcpy(driver_socket.sun_path, sockname);
  +#ifdef SCM_RIGHTS
  +       sock_len = sizeof(driver_socket.sun_family) + strlen(driver_socket.sun_path) 
\
  +         + sizeof(driver_socket.sun_len) +  1;
  +       driver_socket.sun_len = sock_len;
  +#else
  +       sock_len = strlen(driver_socket.sunpath) + sizeof(driver_socket.sun_family);
  +#endif
  +       /* Attempt a connection to the server */
  +       if ( connect(driver_fd, (struct sockaddr *) &driver_socket, sock_len) < 0)
  +         {
  +           perror("connect() in pexecute()");
  +         }
  +       else
  +         {
  +           flag_using_server = 1;
  +           /* Now send stdin, stdout and stderr file descriptors */
  +           /* Followed by argc, and serialized argv */
  +           if ( (send_fd(driver_fd, input_desc) < 0))
  +             {
  +               perror("sendmsg");
  +               flag_using_server = 0;
  +             }
  +           else
  +             if ( (send_fd(driver_fd, output_desc) < 0))
  +               {
  +                 perror("sendmsg");
  +                 flag_using_server = 0;
  +               }
  +             else
  +               if ( (send_fd(driver_fd, STDERR_FILENO) < 0))
  +                 {
  +                   perror("sendmsg");
  +                   flag_using_server = 0;
  +                 }
  +           /* Now send serialized argv */
  +           /* For now, there will be a static buffer on the server side, perhaps 
change that to dynamic later */
  +           /* We may want to implement an acknowledgement sequence here, and 
compare a simple checksum of the arguments vector */
  +           if (flag_using_server)
  +             {
  +               char driver_args[8192];
  +               int totalargsize = 0;
  +               
  +               for (argpos = 0; argv[argpos]; argpos++)
  +                 {
  +                   strcpy(driver_args+totalargsize, argv[argpos]);
  +                   totalargsize += strlen(argv[argpos]) + 1;
  +                 }
  +               /* Termination character */
  +               strcpy(driver_args+totalargsize, "\0");
  +               if ( write(driver_fd, driver_args, totalargsize+1) < totalargsize+1)
  +                 {
  +                   perror("write() in execute()");
  +                   flag_using_server = 0;
  +                 }
  +
  +               /* We will block on this read, waiting for the go ahead sequence 
from the server; it may not arrive until the server decides the system is sufficiently 
idle to handle another parallel compilation */
  +               if (read (driver_fd, ga, 3) < 0)
  +                 {
  +                   flag_using_server = 0;
  +                   fprintf(stderr, "read failed in pexecute()\n");
  +                 }
  +               else
  +                 if ( 0 != strcmp(ga, "GA"))
  +                   {
  +                     fprintf(stderr, "Did not receive GA in pexecute()\n");
  +                     flag_using_server = 0;
  +                   }
  +               /* Look for PFE ok go ahead sequence here */
  +               if (flag_using_server)
  +                 {
  +                   if (read (driver_fd, ga, 3) < 0)
  +                     {
  +                       flag_using_server = 0;
  +                       fprintf(stderr, "ppfe read failed in pexecute()\n");
  +                     }
  +                   else
  +                     if ( 0 != strcmp(ga, "PG"))
  +                       {
  +                         fprintf(stderr, "Did not receive PG in pexecute()\n");
  +                         flag_using_server = 0;
  +                       }
  +                 }
  +             }
  +         }
  +       close(driver_fd);
  +       if (flag_using_server)
  +         {
  +           if (input_desc != STDIN_FILE_NO)
  +             close (input_desc);
  +           if (output_desc != STDOUT_FILE_NO)
  +             close (output_desc);
  +         }
  +     }
       }
  +  else
  +    flag_using_server = 0;
   
  +    if (0 == flag_using_server)
  +      {
  +      /* APPLE LOCAL end */
  +  /* Fork a subprocess; wait and retry if it fails.  */
  +     sleep_interval = 1;
  +     pid = -1;
  +     for (retries = 0; retries < 4; retries++)
  +       {
  +         pid = fork ();
  +         if (pid >= 0)
  +           break;
  +         sleep (sleep_interval);
  +         sleep_interval *= 2;
  +       }
  +     /* APPLE LOCAL begin compilation server */
  +      }
  +    else
  +      {
  +     pid = -42;
  +     return pid;
  +      }
  +    /* APPLE LOCAL end */
     switch (pid)
       {
       case -1:
  
  
  


Reply via email to