From 5790ef40bae85dc23ae404098198879106057697 Mon Sep 17 00:00:00 2001 From: Dan Nicolaescu Date: Sun, 26 Oct 2008 19:05:47 +0000 Subject: [PATCH] * startup.el (command-line): Call daemon-initialized after starting the server. * emacs.c (daemon_pipe): New variable (main): Create a pipe before forking, make the parent exit only after the child has closed its end of the pipe. Move closing the descriptors ... (Fdaemon_initialized): ... here. New function. --- lisp/ChangeLog | 5 +++ lisp/startup.el | 3 +- src/ChangeLog | 8 +++++ src/emacs.c | 83 ++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 90 insertions(+), 9 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index dcb6b1adbb2..9175fe33918 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2008-10-26 Romain Francoise + + * startup.el (command-line): Call daemon-initialized after + starting the server. + 2008-10-26 Kenichi Handa * help-fns.el (describe-categories): Display the terse legend at diff --git a/lisp/startup.el b/lisp/startup.el index 1c39c8c95f5..7b7fbb2fd68 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1213,7 +1213,8 @@ the `--debug-init' option to view a complete error backtrace." ;; processing all command line arguments to allow e.g. `server-name' ;; to be changed before the server starts. (when (daemonp) - (server-start)) + (server-start) + (daemon-initialized)) ;; Run emacs-session-restore (session management) if started by ;; the session manager and we have a session manager connection. diff --git a/src/ChangeLog b/src/ChangeLog index 3dd47c8484b..f86b94ed7d8 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2008-10-26 Romain Francoise + + * emacs.c (daemon_pipe): New variable + (main): Create a pipe before forking, make the parent exit only after + the child has closed its end of the pipe. Move closing the + descriptors ... + (Fdaemon_initialized): ... here. New function. + 2008-10-26 Stefan Monnier * chartab.c (Foptimize_char_table): Make sure `ascii' doesn't point to diff --git a/src/emacs.c b/src/emacs.c index 4712e9c1d0b..bcc7fb05792 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -238,6 +238,10 @@ int noninteractive1; /* Nonzero means Emacs was started as a daemon. */ int is_daemon = 0; +/* Pipe used to send exit notification to the daemon parent at + startup. */ +static int daemon_pipe[2]; + /* Save argv and argc. */ char **initial_argv; int initial_argc; @@ -1073,21 +1077,54 @@ main (int argc, char **argv) if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args)) { #ifndef DOS_NT - pid_t f = fork (); - int nfd; + pid_t f; + + /* Start as a daemon: fork a new child process which will run the + rest of the initialization code, then exit. + + We want to avoid exiting before the server socket is ready, so + use a pipe for synchronization. The parent waits for the child + to close its end of the pipe (using `daemon-initialized') + before exiting. */ + if (pipe (daemon_pipe) == -1) + { + fprintf (stderr, "Cannot pipe!\n"); + exit (1); + } + + f = fork (); if (f > 0) - exit (0); + { + int retval; + char buf[1]; + + /* Close unused writing end of the pipe. */ + close (daemon_pipe[1]); + + /* Just wait for the child to close its end of the pipe. */ + do + { + retval = read (daemon_pipe[0], &buf, 1); + } + while (retval == -1 && errno == EINTR); + + if (retval < 0) + { + fprintf (stderr, "Error reading status from child\n"); + exit (1); + } + + close (daemon_pipe[0]); + exit (0); + } if (f < 0) { fprintf (stderr, "Cannot fork!\n"); exit (1); } - nfd = open ("/dev/null", O_RDWR); - dup2 (nfd, 0); - dup2 (nfd, 1); - dup2 (nfd, 2); - close (nfd); + /* Close unused reading end of the pipe. */ + close (daemon_pipe[0]); is_daemon = 1; #ifdef HAVE_SETSID setsid(); @@ -2388,6 +2425,35 @@ DEFUN ("daemonp", Fdaemonp, Sdaemonp, 0, 0, 0, return is_daemon ? Qt : Qnil; } +DEFUN ("daemon-initialized", Fdaemon_initialized, Sdaemon_initialized, 0, 0, 0, + doc: /* Mark the Emacs daemon as being initialized. */) + () +{ + int nfd; + + if (!is_daemon) + error ("This function can only be called if emacs is run as a daemon"); + + if (daemon_pipe[1] < 0) + error ("The daemon has already been initialized"); + + if (NILP (Vafter_init_time)) + error ("This function can only be called after loading the init files"); + + /* Get rid of stdin, stdout and stderr. */ + open ("/dev/null", O_RDWR); + dup2 (nfd, 0); + dup2 (nfd, 1); + dup2 (nfd, 2); + close (nfd); + + /* Closing the pipe will notify the parent that it can exit. */ + close (daemon_pipe[1]); + /* Set it to an invalid value so we know we've already run this function. */ + daemon_pipe[1] = -1; + return Qt; +} + void syms_of_emacs () { @@ -2407,6 +2473,7 @@ syms_of_emacs () defsubr (&Sinvocation_name); defsubr (&Sinvocation_directory); defsubr (&Sdaemonp); + defsubr (&Sdaemon_initialized); DEFVAR_LISP ("command-line-args", &Vcommand_line_args, doc: /* Args passed by shell to Emacs, as a list of strings. -- 2.39.2