X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/40da115367cb5eb8a19bf9556acec9d6e02fac09..9250c1e82544edcc8bf62ec9a5149e575fa3c73f:/src/emacs.c diff --git a/src/emacs.c b/src/emacs.c index 68127df0c0..3e94f0fc6c 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1,6 +1,6 @@ /* Fully extensible Emacs, running on Unix, intended for GNU. Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1997, 1998, 1999, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -106,7 +106,7 @@ int gdb_use_union = 1; #endif EMACS_INT gdb_valbits = VALBITS; EMACS_INT gdb_gctypebits = GCTYPEBITS; -#ifdef DATA_SEG_BITS +#if defined (DATA_SEG_BITS) && ! defined (USE_LSB_TAG) EMACS_INT gdb_data_seg_bits = DATA_SEG_BITS; #else EMACS_INT gdb_data_seg_bits = 0; @@ -131,6 +131,9 @@ Lisp_Object Vinvocation_directory; nil means get them only from PATH_LOADSEARCH. */ Lisp_Object Vinstallation_directory; +/* The values of `current-time' before and after Emacs initialization. */ +Lisp_Object Vbefore_init_time, Vafter_init_time; + /* Hook run by `kill-emacs' before it does really anything. */ Lisp_Object Vkill_emacs_hook; @@ -199,6 +202,10 @@ extern int inherited_pgroup; int display_arg; #endif +#ifdef HAVE_NS +extern char ns_no_defaults; +#endif + /* An address near the bottom of the stack. Tells GC how to save a copy of the stack. */ char *stack_bottom; @@ -209,8 +216,8 @@ static void *my_heap_start; /* The gap between BSS end and heap start as far as we can tell. */ static unsigned long heap_bss_diff; -/* If the gap between BSS end and heap start is larger than this we try to - work around it, and if that fails, output a warning in dump-emacs. */ +/* If the gap between BSS end and heap start is larger than this + output a warning in dump-emacs. */ #define MAX_HEAP_BSS_DIFF (1024*1024) @@ -232,6 +239,13 @@ int noninteractive; int noninteractive1; +/* Name for the server started by the daemon.*/ +static char *daemon_name; + +/* Pipe used to send exit notification to the daemon parent at + startup. */ +int daemon_pipe[2]; + /* Save argv and argc. */ char **initial_argv; int initial_argc; @@ -254,6 +268,7 @@ read the main documentation for these command-line arguments.\n\ Initialization options:\n\ \n\ --batch do not do interactive display; implies -q\n\ +--daemon start a server in the background\n\ --debug-init enable Emacs Lisp debugger for init file\n\ --display, -d DISPLAY use X server DISPLAY\n\ --multibyte, --no-unibyte inhibit the effect of EMACS_UNIBYTE\n\ @@ -274,8 +289,8 @@ Initialization options:\n\ Action options:\n\ \n\ FILE visit FILE using find-file\n\ -+LINE go to line LINE in next FILE\n\ -+LINE:COLUMN go to line LINE, column COLUMN, in next FILE\n\ ++LINE go to line LINE in next FILE\n\ ++LINE:COLUMN go to line LINE, column COLUMN, in next FILE\n\ --directory, -L DIR add DIR to variable load-path\n\ --eval EXPR evaluate Emacs Lisp expression EXPR\n\ --execute EXPR evaluate Emacs Lisp expression EXPR\n\ @@ -785,6 +800,10 @@ main (int argc, char **argv) #endif int no_loadup = 0; char *junk = 0; + char *dname_arg = 0; +#ifdef NS_IMPL_COCOA + char dname_arg2[80]; +#endif #if GC_MARK_STACK extern Lisp_Object *stack_base; @@ -854,29 +873,24 @@ main (int argc, char **argv) } #ifdef HAVE_PERSONALITY_LINUX32 - /* See if there is a gap between the end of BSS and the heap. - In that case, set personality and exec ourself again. */ if (!initialized && (strcmp (argv[argc-1], "dump") == 0 || strcmp (argv[argc-1], "bootstrap") == 0) - && heap_bss_diff > MAX_HEAP_BSS_DIFF) + && ! getenv ("EMACS_HEAP_EXEC")) { - if (! getenv ("EMACS_HEAP_EXEC")) - { - /* Set this so we only do this once. */ - putenv("EMACS_HEAP_EXEC=true"); + /* Set this so we only do this once. */ + putenv("EMACS_HEAP_EXEC=true"); - /* A flag to turn off address randomization which is introduced - in linux kernel shipped with fedora core 4 */ + /* A flag to turn off address randomization which is introduced + in linux kernel shipped with fedora core 4 */ #define ADD_NO_RANDOMIZE 0x0040000 - personality (PER_LINUX32 | ADD_NO_RANDOMIZE); + personality (PER_LINUX32 | ADD_NO_RANDOMIZE); #undef ADD_NO_RANDOMIZE - execvp (argv[0], argv); + execvp (argv[0], argv); - /* If the exec fails, try to dump anyway. */ - perror ("execvp"); - } + /* If the exec fails, try to dump anyway. */ + perror ("execvp"); } #endif /* HAVE_PERSONALITY_LINUX32 */ @@ -1068,6 +1082,141 @@ main (int argc, char **argv) exit (0); } + if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args) + || argmatch (argv, argc, "-daemon", "--daemon", 5, &dname_arg, &skip_args)) + { +#ifndef DOS_NT + pid_t f; + + /* Start as a daemon: fork a new child process which will run the + rest of the initialization code, then exit. + + Detaching a daemon requires the following steps: + - fork + - setsid + - exit the parent + - close the tty file-descriptors + + We only want to do the last 2 steps once the daemon is ready to + serve requests, i.e. after loading .emacs (initialization). + OTOH initialization may start subprocesses (e.g. ispell) and these + should be run from the proper process (the one that will end up + running as daemon) and with the proper "session id" in order for + them to keep working after detaching, so fork and setsid need to be + performed before initialization. + + 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); + } + +#ifndef NS_IMPL_COCOA + f = fork (); +#else /* NS_IMPL_COCOA */ + /* Under Cocoa we must do fork+exec as CoreFoundation lib fails in + forked process: http://developer.apple.com/ReleaseNotes/ + CoreFoundation/CoreFoundation.html) + We mark being in the exec'd process by a daemon name argument of + form "--daemon=\nFD0,FD1\nNAME" where FD are the pipe file descriptors, + NAME is the original daemon name, if any. */ + if (!dname_arg || !strchr (dname_arg, '\n')) + f = fork (); /* in orig */ + else + f = 0; /* in exec'd */ +#endif /* NS_IMPL_COCOA */ + 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); + } + else if (retval == 0) + { + fprintf (stderr, "Error: server did not start correctly\n"); + exit (1); + } + + close (daemon_pipe[0]); + exit (0); + } + if (f < 0) + { + fprintf (stderr, "Cannot fork!\n"); + exit (1); + } + +#ifdef NS_IMPL_COCOA + { + /* In orig process, forked as child, OR in exec'd. */ + if (!dname_arg || !strchr (dname_arg, '\n')) + { /* In orig, child: now exec w/special daemon name. */ + char fdStr[80]; + + if (dname_arg && strlen (dname_arg) > 70) + { + fprintf (stderr, "daemon: child name too long\n"); + exit (1); + } + + sprintf (fdStr, "--daemon=\n%d,%d\n%s", daemon_pipe[0], + daemon_pipe[1], dname_arg ? dname_arg : ""); + argv[skip_args] = fdStr; + + execv (argv[0], argv); + fprintf (stderr, "emacs daemon: exec failed: %d\t%d\n", errno); + exit (1); + } + + /* In exec'd: parse special dname into pipe and name info. */ + if (!dname_arg || !strchr (dname_arg, '\n') + || strlen (dname_arg) < 1 || strlen (dname_arg) > 70) + { + fprintf (stderr, "emacs daemon: daemon name absent or too long\n"); + exit(1); + } + dname_arg2[0] = '\0'; + sscanf (dname_arg, "\n%d,%d\n%s", &(daemon_pipe[0]), &(daemon_pipe[1]), + dname_arg2); + dname_arg = strlen (dname_arg2) ? dname_arg2 : NULL; + } +#endif /* NS_IMPL_COCOA */ + + if (dname_arg) + daemon_name = xstrdup (dname_arg); + /* Close unused reading end of the pipe. */ + close (daemon_pipe[0]); + /* Make sure that the used end of the pipe is closed on exec, so + that it is not accessible to programs started from .emacs. */ + fcntl (daemon_pipe[1], F_SETFD, FD_CLOEXEC); + +#ifdef HAVE_SETSID + setsid(); +#endif +#else /* DOS_NT */ + fprintf (stderr, "This platform does not support the -daemon flag.\n"); + exit (1); +#endif /* DOS_NT */ + } + if (! noninteractive) { #ifdef BSD_PGRPS @@ -1329,6 +1478,16 @@ main (int argc, char **argv) { char *tmp; display_arg = 4; + if (argmatch (argv, argc, "-q", "--no-init-file", 6, NULL, &skip_args)) + { + ns_no_defaults = 1; + skip_args--; + } + if (argmatch (argv, argc, "-Q", "--quick", 5, NULL, &skip_args)) + { + ns_no_defaults = 1; + skip_args--; + } #ifdef NS_IMPL_COCOA if (skip_args < argc) { @@ -1719,6 +1878,7 @@ struct standard_args standard_args[] = { "-nw", "--no-windows", 110, 0 }, { "-batch", "--batch", 100, 0 }, { "-script", "--script", 100, 1 }, + { "-daemon", "--daemon", 99, 0 }, { "-help", "--help", 90, 0 }, { "-no-unibyte", "--no-unibyte", 83, 0 }, { "-multibyte", "--multibyte", 82, 0 }, @@ -2350,6 +2510,58 @@ decode_env_path (evarname, defalt) return Fnreverse (lpath); } +DEFUN ("daemonp", Fdaemonp, Sdaemonp, 0, 0, 0, + doc: /* Return non-nil if the current emacs process is a daemon. +If the daemon was given a name argument, return that name. */) + () +{ + if (IS_DAEMON) + if (daemon_name) + return build_string (daemon_name); + else + return Qt; + else + return Qnil; +} + +DEFUN ("daemon-initialized", Fdaemon_initialized, Sdaemon_initialized, 0, 0, 0, + doc: /* Mark the Emacs daemon as being initialized. +This finishes the daemonization process by doing the other half of detaching +from the parent process and its tty file descriptors. */) + () +{ + 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. */ + nfd = 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. + FIXME: In case some other process inherited the pipe, closing it here + won't notify the parent because it's still open elsewhere, so we + additionally send a byte, just to make sure the parent really exits. + Instead, we should probably close the pipe in start-process and + call-process to make sure the pipe is never inherited by + subprocesses. */ + write (daemon_pipe[1], "\n", 1); + 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 () { @@ -2368,6 +2580,8 @@ 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. @@ -2456,6 +2670,18 @@ was found. */); DEFVAR_LISP ("previous-system-time-locale", &Vprevious_system_time_locale, doc: /* Most recently used system locale for time. */); Vprevious_system_time_locale = Qnil; + + DEFVAR_LISP ("before-init-time", &Vbefore_init_time, + doc: /* Value of `current-time' before Emacs begins initialization. */); + Vbefore_init_time = Qnil; + + DEFVAR_LISP ("after-init-time", &Vafter_init_time, + doc: /* Value of `current-time' after loading the init files. +This is nil during initialization. */); + Vafter_init_time = Qnil; + + /* Make sure IS_DAEMON starts up as false. */ + daemon_pipe[1] = 0; } /* arch-tag: 7bfd356a-c720-4612-8ab6-aa4222931c2e