This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[cs] last c-only set of patches: gcc.c toplev.c
- From: Per Bothner <per at bothner dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 15 Aug 2003 18:00:53 -0700
- Subject: [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)