GNU bug report logs - #1058
23.0.60; emacs --daemon should not return until socket is ready

Previous Next

Package: emacs;

Reported by: SRS0+wOMF+22+gmail.com=trentbuck <at> internode.on.net

Date: Tue, 30 Sep 2008 14:10:04 UTC

Severity: normal

Done: Chong Yidong <cyd <at> stupidchicken.com>

Bug is archived. No further changes may be made.

Full log


Message #113 received at 1058 <at> emacsbugs.donarmstrong.com (full text, mbox):

From: Dan Nicolaescu <dann <at> ics.uci.edu>
To: Romain Francoise <romain <at> orebokech.com>
Cc: 1058 <at> debbugs.gnu.org, trentbuck <at> gmail.com
Subject: Re: bug#1058: 23.0.60; emacs --daemon should not return until socket is ready
Date: Mon, 6 Oct 2008 13:59:36 -0700 (PDT)
Romain Francoise <romain <at> orebokech.com> writes:

  > Here's version one of a patch for this, please let me know what you
  > think.

Here's a version based on your code that also moves detaching from the
terminal later.  emacs --daemon && emacsclient -c works.
Errors in ~/.emacs show up in the *Messages* buffer (as they do when
starting up normally). 
Only lightly tested.  Looking at the patch again, I there aren't any new
features here, so it can go in as a bug fix.

Index: lisp/startup.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/startup.el,v
retrieving revision 1.508
diff -u -3 -p -r1.508 startup.el
--- lisp/startup.el	6 Oct 2008 16:16:30 -0000	1.508
+++ lisp/startup.el	6 Oct 2008 20:18:41 -0000
@@ -1219,7 +1219,7 @@ opening the first frame (e.g. open a con
   ;; processing all command line arguments to allow e.g. `server-name'
   ;; to be changed before the server starts.
   (when (daemonp)
-    (server-start))
+    (daemon-detach-and-start-server))
 
   ;; Run emacs-session-restore (session management) if started by
   ;; the session manager and we have a session manager connection.
Index: src/emacs.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/emacs.c,v
retrieving revision 1.448
diff -u -3 -p -r1.448 emacs.c
--- src/emacs.c	6 Oct 2008 16:16:56 -0000	1.448
+++ src/emacs.c	6 Oct 2008 20:18:41 -0000
@@ -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;
@@ -1078,25 +1082,7 @@ main (int argc, char **argv)
   if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args))
     {
 #ifndef DOS_NT
-      pid_t f = fork ();
-      int nfd;
-      if (f > 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);
       is_daemon = 1;
-#ifdef HAVE_SETSID
-      setsid();
-#endif
 #else /* DOS_NT */
       fprintf (stderr, "This platform does not support the -daemon flag.\n");
       exit (1);
@@ -2393,6 +2379,87 @@ DEFUN ("daemonp", Fdaemonp, Sdaemonp, 0,
   return is_daemon ? Qt : Qnil;
 }
 
+
+DEFUN ("daemon-detach-and-start-server", Fdaemon_detach_and_start_server, Sdaemon_detach_and_start_server, 0, 0, 0,
+       doc: /* Detach from terminal and start the server */)
+  ()
+{
+  static char daemon_initialized = 0;
+  pid_t f;
+  int nfd;
+
+  if (!is_daemon)
+    error ("This function can only be called if emacs is run as a daemon");
+
+  if (daemon_initialized)
+    error ("The daemon has already been initialized");
+
+  if (NILP (Vafter_init_time))
+    error ("This function can only be called after loading the init files");
+  
+  /* 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)
+    {
+      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);
+    }
+
+  /* Close unused reading end of the pipe.  */
+  close (daemon_pipe[0]);
+
+  nfd = open ("/dev/null", O_RDWR);
+  dup2 (nfd, 0);
+  dup2 (nfd, 1);
+  dup2 (nfd, 2);
+  close (nfd);
+  is_daemon = 1;
+#ifdef HAVE_SETSID
+  setsid();
+#endif
+  call0 (intern ("server-start"));
+
+  /* Closing the pipe will notify the parent that it can exit. */
+  close (daemon_pipe[1]);
+  daemon_initialized = 1;
+}
+
 void
 syms_of_emacs ()
 {
@@ -2412,6 +2479,7 @@ syms_of_emacs ()
   defsubr (&Sinvocation_name);
   defsubr (&Sinvocation_directory);
   defsubr (&Sdaemonp);
+  defsubr (&Sdaemon_detach_and_start_server);
 
   DEFVAR_LISP ("command-line-args", &Vcommand_line_args,
 	       doc: /* Args passed by shell to Emacs, as a list of strings.




This bug report was last modified 16 years and 202 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.