X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/cf2d22b874ca2df0072e32ee641e8efffe4abd6d..47571310770234371eb6e361214056efd1b67137:/src/sysdep.c diff --git a/src/sysdep.c b/src/sysdep.c index 06dc41b511..c5b3c43ea6 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1,6 +1,6 @@ /* Interfaces to system-dependent kernel and library entries. - Copyright (C) 1985-1988, 1993-1995, 1999-2012 - Free Software Foundation, Inc. + Copyright (C) 1985-1988, 1993-1995, 1999-2014 Free Software + Foundation, Inc. This file is part of GNU Emacs. @@ -19,10 +19,8 @@ along with GNU Emacs. If not, see . */ #include -#define SYSTIME_INLINE EXTERN_INLINE - #include -#include +#include "sysstdio.h" #ifdef HAVE_PWD_H #include #include @@ -30,25 +28,26 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include -#include -#include #include #include "lisp.h" #include "sysselect.h" #include "blockinput.h" -#ifdef BSD_SYSTEM -#include -#include +#if defined DARWIN_OS || defined __FreeBSD__ +# include #endif #ifdef __FreeBSD__ -#include -#include -#include +/* Sparc/ARM machine/frame.h has 'struct frame' which conflicts with Emacs's + 'struct frame', so rename it. */ +# define frame freebsd_frame +# include +# undef frame + +# include +# include #endif #ifdef WINDOWSNT @@ -71,9 +70,9 @@ along with GNU Emacs. If not, see . */ #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */ #include "msdos.h" -#include #endif +#include #include #include @@ -101,14 +100,13 @@ along with GNU Emacs. If not, see . */ #define _P_WAIT 0 int _cdecl _spawnlp (int, const char *, const char *, ...); int _cdecl _getpid (void); -extern char *getwd (char *); #endif #include "syssignal.h" #include "systime.h" -static int emacs_get_tty (int, struct emacs_tty *); -static int emacs_set_tty (int, struct emacs_tty *, int); +void emacs_get_tty (int, struct emacs_tty *) EXTERNALLY_VISIBLE; +int emacs_set_tty (int, struct emacs_tty *, bool) EXTERNALLY_VISIBLE; /* ULLONG_MAX is missing on Red Hat Linux 7.3; see Bug#11781. */ #ifndef ULLONG_MAX @@ -130,16 +128,16 @@ static const int baud_convert[] = /* Return the current working directory. Returns NULL on errors. Any other returned value must be freed with free. This is used only when get_current_dir_name is not defined on the system. */ -char* +char * get_current_dir_name (void) { char *buf; - char *pwd; + char *pwd = getenv ("PWD"); struct stat dotstat, pwdstat; - /* If PWD is accurate, use it instead of calling getwd. PWD is + /* If PWD is accurate, use it instead of calling getcwd. PWD is sometimes a nicer name, and using it may avoid a fatal error if a parent directory is searchable but not readable. */ - if ((pwd = getenv ("PWD")) != 0 + if (pwd && (IS_DIRECTORY_SEP (*pwd) || (*pwd && IS_DEVICE_SEP (pwd[1]))) && stat (pwd, &pwdstat) == 0 && stat (".", &dotstat) == 0 @@ -155,7 +153,6 @@ get_current_dir_name (void) return NULL; strcpy (buf, pwd); } -#ifdef HAVE_GETCWD else { size_t buf_size = 1024; @@ -179,22 +176,6 @@ get_current_dir_name (void) return NULL; } } -#else - else - { - /* We need MAXPATHLEN here. */ - buf = malloc (MAXPATHLEN + 1); - if (!buf) - return NULL; - if (getwd (buf) == NULL) - { - int tmp_errno = errno; - free (buf); - errno = tmp_errno; - return NULL; - } - } -#endif return buf; } #endif @@ -241,7 +222,9 @@ discard_tty_input (void) void stuff_char (char c) { - if (! FRAME_TERMCAP_P (SELECTED_FRAME ())) + if (! (FRAMEP (selected_frame) + && FRAME_LIVE_P (XFRAME (selected_frame)) + && FRAME_TERMCAP_P (XFRAME (selected_frame)))) return; /* Should perhaps error if in batch mode */ @@ -274,7 +257,7 @@ init_baud_rate (int fd) #endif /* not DOS_NT */ } - baud_rate = (emacs_ospeed < sizeof baud_convert / sizeof baud_convert[0] + baud_rate = (emacs_ospeed < ARRAYELTS (baud_convert) ? baud_convert[emacs_ospeed] : 9600); if (baud_rate == 0) baud_rate = 1200; @@ -284,57 +267,76 @@ init_baud_rate (int fd) #ifndef MSDOS -static void -wait_for_termination_1 (pid_t pid, int interruptible) +/* Wait for the subprocess with process id CHILD to terminate or change status. + CHILD must be a child process that has not been reaped. + If STATUS is non-null, store the waitpid-style exit status into *STATUS + and tell wait_reading_process_output that it needs to look around. + Use waitpid-style OPTIONS when waiting. + If INTERRUPTIBLE, this function is interruptible by a signal. + + Return CHILD if successful, 0 if no status is available; + the latter is possible only when options & NOHANG. */ +static pid_t +get_child_status (pid_t child, int *status, int options, bool interruptible) { - while (1) + pid_t pid; + + /* Invoke waitpid only with a known process ID; do not invoke + waitpid with a nonpositive argument. Otherwise, Emacs might + reap an unwanted process by mistake. For example, invoking + waitpid (-1, ...) can mess up glib by reaping glib's subprocesses, + so that another thread running glib won't find them. */ + eassert (child > 0); + + while ((pid = waitpid (child, status, options)) < 0) { - int status; - int wait_result = waitpid (pid, &status, 0); - if (wait_result < 0) - { - if (errno != EINTR) - break; - } - else - { - record_child_status_change (wait_result, status); - break; - } + /* Check that CHILD is a child process that has not been reaped, + and that STATUS and OPTIONS are valid. Otherwise abort, + as continuing after this internal error could cause Emacs to + become confused and kill innocent-victim processes. */ + if (errno != EINTR) + emacs_abort (); /* Note: the MS-Windows emulation of waitpid calls QUIT internally. */ if (interruptible) QUIT; } -} -/* Wait for subprocess with process id `pid' to terminate and - make sure it will get eliminated (not remain forever as a zombie) */ + /* If successful and status is requested, tell wait_reading_process_output + that it needs to wake up and look around. */ + if (pid && status && input_available_clear_time) + *input_available_clear_time = make_timespec (0, 0); -void -wait_for_termination (pid_t pid) -{ - wait_for_termination_1 (pid, 0); + return pid; } -/* Like the above, but allow keyboard interruption. */ +/* Wait for the subprocess with process id CHILD to terminate. + CHILD must be a child process that has not been reaped. + If STATUS is non-null, store the waitpid-style exit status into *STATUS + and tell wait_reading_process_output that it needs to look around. + If INTERRUPTIBLE, this function is interruptible by a signal. */ void -interruptible_wait_for_termination (pid_t pid) +wait_for_termination (pid_t child, int *status, bool interruptible) { - wait_for_termination_1 (pid, 1); + get_child_status (child, status, 0, interruptible); } -/* - * flush any pending output - * (may flush input as well; it does not matter the way we use it) - */ +/* Report whether the subprocess with process id CHILD has changed status. + Termination counts as a change of status. + CHILD must be a child process that has not been reaped. + If STATUS is non-null, store the waitpid-style exit status into *STATUS + and tell wait_reading_process_output that it needs to look around. + Use waitpid-style OPTIONS to check status, but do not wait. -void -flush_pending_output (int channel) + Return CHILD if successful, 0 if no status is available because + the process's state has not changed. */ +pid_t +child_status_changed (pid_t child, int *status, int options) { - /* FIXME: maybe this function should be removed */ + return get_child_status (child, status, WNOHANG | options, 0); } + /* Set up the terminal at the other end of a pseudo-terminal that we will be controlling an inferior through. @@ -446,20 +448,15 @@ static void restore_signal_handlers (struct save_signal *); void sys_suspend (void) { -#if defined (SIGTSTP) && !defined (MSDOS) - - { - pid_t pgrp = getpgrp (); - EMACS_KILLPG (pgrp, SIGTSTP); - } - -#else /* No SIGTSTP */ +#ifndef DOS_NT + kill (0, SIGTSTP); +#else /* On a system where suspending is not implemented, instead fork a subshell and let it talk directly to the terminal while we wait. */ sys_subshell (); -#endif /* no SIGTSTP */ +#endif } /* Fork a subshell. */ @@ -469,14 +466,29 @@ sys_subshell (void) { #ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */ int st; +#ifdef MSDOS char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */ +#else + char oldwd[MAX_UTF8_PATH]; #endif - int pid; +#endif + pid_t pid; + int status; struct save_signal saved_handlers[5]; - Lisp_Object dir; - unsigned char *volatile str_volatile = 0; - unsigned char *str; - int len; + char *str = SSDATA (encode_current_directory ()); + +#ifdef DOS_NT + pid = 0; +#else + { + char *volatile str_volatile = str; + pid = vfork (); + str = str_volatile; + } +#endif + + if (pid < 0) + error ("Can't spawn subshell"); saved_handlers[0].code = SIGINT; saved_handlers[1].code = SIGQUIT; @@ -488,32 +500,8 @@ sys_subshell (void) saved_handlers[3].code = 0; #endif - /* Mentioning current_buffer->buffer would mean including buffer.h, - which somehow wedges the hp compiler. So instead... */ - - dir = intern ("default-directory"); - if (NILP (Fboundp (dir))) - goto xyzzy; - dir = Fsymbol_value (dir); - if (!STRINGP (dir)) - goto xyzzy; - - dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil); - str_volatile = str = alloca (SCHARS (dir) + 2); - len = SCHARS (dir); - memcpy (str, SDATA (dir), len); - if (str[len - 1] != '/') str[len++] = '/'; - str[len] = 0; - xyzzy: - #ifdef DOS_NT - pid = 0; save_signal_handlers (saved_handlers); - synch_process_alive = 1; -#else - pid = vfork (); - if (pid == -1) - error ("Can't spawn subshell"); #endif if (pid == 0) @@ -521,27 +509,24 @@ sys_subshell (void) const char *sh = 0; #ifdef DOS_NT /* MW, Aug 1993 */ - getwd (oldwd); + getcwd (oldwd, sizeof oldwd); if (sh == 0) - sh = (char *) egetenv ("SUSPEND"); /* KFS, 1994-12-14 */ + sh = egetenv ("SUSPEND"); /* KFS, 1994-12-14 */ #endif if (sh == 0) - sh = (char *) egetenv ("SHELL"); + sh = egetenv ("SHELL"); if (sh == 0) sh = "sh"; /* Use our buffer's default directory for the subshell. */ - str = str_volatile; - if (str && chdir ((char *) str) != 0) + if (chdir (str) != 0) { #ifndef DOS_NT - ignore_value (write (1, "Can't chdir\n", 12)); - _exit (1); + emacs_perror (str); + _exit (EXIT_CANCELED); #endif } - close_process_descs (); /* Close Emacs's pipes/ptys */ - #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */ { char *epwd = getenv ("PWD"); @@ -551,8 +536,6 @@ sys_subshell (void) if (epwd) { strcpy (old_pwd, epwd); - if (str[len - 1] == '/') - str[len - 1] = '\0'; setenv ("PWD", str, 1); } st = system (sh); @@ -569,8 +552,8 @@ sys_subshell (void) write (1, "Can't execute subshell", 22); #else /* not WINDOWSNT */ execlp (sh, sh, (char *) 0); - ignore_value (write (1, "Can't execute subshell", 22)); - _exit (1); + emacs_perror (sh); + _exit (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE); #endif /* not WINDOWSNT */ #endif /* not MSDOS */ } @@ -578,14 +561,12 @@ sys_subshell (void) /* Do this now if we did not do it before. */ #ifndef MSDOS save_signal_handlers (saved_handlers); - synch_process_alive = 1; #endif #ifndef DOS_NT - wait_for_termination (pid); + wait_for_termination (pid, &status, 0); #endif restore_signal_handlers (saved_handlers); - synch_process_alive = 0; } static void @@ -611,7 +592,7 @@ restore_signal_handlers (struct save_signal *saved_handlers) } #ifdef USABLE_SIGIO -static int old_fcntl_flags[MAXDESC]; +static int old_fcntl_flags[FD_SETSIZE]; #endif void @@ -624,6 +605,7 @@ init_sigio (int fd) #endif } +#ifndef DOS_NT static void reset_sigio (int fd) { @@ -631,6 +613,7 @@ reset_sigio (int fd) fcntl (fd, F_SETFL, old_fcntl_flags[fd]); #endif } +#endif void request_sigio (void) @@ -678,7 +661,29 @@ ignore_sigio (void) signal (SIGIO, SIG_IGN); #endif } + +#ifndef MSDOS +/* Block SIGCHLD. */ + +void +block_child_signal (sigset_t *oldset) +{ + sigset_t blocked; + sigemptyset (&blocked); + sigaddset (&blocked, SIGCHLD); + sigaddset (&blocked, SIGINT); + pthread_sigmask (SIG_BLOCK, &blocked, oldset); +} + +/* Unblock SIGCHLD. */ + +void +unblock_child_signal (sigset_t const *oldset) +{ + pthread_sigmask (SIG_SETMASK, oldset, 0); +} +#endif /* !MSDOS */ /* Saving and restoring the process group of Emacs's terminal. */ @@ -710,6 +715,27 @@ init_foreground_group (void) inherited_pgroup = getpid () == pgrp ? 0 : pgrp; } +/* Block and unblock SIGTTOU. */ + +void +block_tty_out_signal (sigset_t *oldset) +{ +#ifdef SIGTTOU + sigset_t blocked; + sigemptyset (&blocked); + sigaddset (&blocked, SIGTTOU); + pthread_sigmask (SIG_BLOCK, &blocked, oldset); +#endif +} + +void +unblock_tty_out_signal (sigset_t const *oldset) +{ +#ifdef SIGTTOU + pthread_sigmask (SIG_SETMASK, oldset, 0); +#endif +} + /* Safely set a controlling terminal FD's process group to PGID. If we are not in the foreground already, POSIX requires tcsetpgrp to deliver a SIGTTOU signal, which would stop us. This is an @@ -721,11 +747,11 @@ static void tcsetpgrp_without_stopping (int fd, pid_t pgid) { #ifdef SIGTTOU - signal_handler_t handler; + sigset_t oldset; block_input (); - handler = signal (SIGTTOU, SIG_IGN); + block_tty_out_signal (&oldset); tcsetpgrp (fd, pgid); - signal (SIGTTOU, handler); + unblock_tty_out_signal (&oldset); unblock_input (); #endif } @@ -751,34 +777,55 @@ widen_foreground_group (int fd) /* Getting and setting emacs_tty structures. */ -/* Set *TC to the parameters associated with the terminal FD. - Return zero if all's well, or -1 if we ran into an error we - couldn't deal with. */ -int +/* Set *TC to the parameters associated with the terminal FD, + or clear it if the parameters are not available. */ +void emacs_get_tty (int fd, struct emacs_tty *settings) { /* Retrieve the primary parameters - baud rate, character size, etcetera. */ -#ifndef DOS_NT - /* We have those nifty POSIX tcmumbleattr functions. */ memset (&settings->main, 0, sizeof (settings->main)); - if (tcgetattr (fd, &settings->main) < 0) - return -1; -#endif +#ifdef DOS_NT +#ifdef WINDOWSNT + HANDLE h = (HANDLE)_get_osfhandle (fd); + DWORD console_mode; - /* We have survived the tempest. */ - return 0; + if (h && h != INVALID_HANDLE_VALUE) + { + if (GetConsoleMode (h, &console_mode)) + settings->main = console_mode; + } +#endif /* WINDOWSNT */ +#else /* !DOS_NT */ + /* We have those nifty POSIX tcmumbleattr functions. */ + tcgetattr (fd, &settings->main); +#endif } /* Set the parameters of the tty on FD according to the contents of - *SETTINGS. If FLUSHP is non-zero, we discard input. - Return 0 if all went well, and -1 if anything failed. */ + *SETTINGS. If FLUSHP, discard input. + Return 0 if all went well, and -1 (setting errno) if anything failed. */ int -emacs_set_tty (int fd, struct emacs_tty *settings, int flushp) +emacs_set_tty (int fd, struct emacs_tty *settings, bool flushp) { /* Set the primary parameters - baud rate, character size, etcetera. */ -#ifndef DOS_NT +#ifdef DOS_NT +#ifdef WINDOWSNT + HANDLE h = (HANDLE)_get_osfhandle (fd); + + if (h && h != INVALID_HANDLE_VALUE) + { + DWORD new_mode; + + /* Assume the handle is open for input. */ + if (flushp) + FlushConsoleInputBuffer (h); + new_mode = settings->main; + SetConsoleMode (h, new_mode); + } +#endif /* WINDOWSNT */ +#else /* !DOS_NT */ int i; /* We have those nifty POSIX tcmumbleattr functions. William J. Smith writes: @@ -825,7 +872,7 @@ emacs_set_tty (int fd, struct emacs_tty *settings, int flushp) #ifdef F_SETOWN -static int old_fcntl_owner[MAXDESC]; +static int old_fcntl_owner[FD_SETSIZE]; #endif /* F_SETOWN */ /* This may also be defined in stdio, @@ -1036,8 +1083,7 @@ init_sys_modes (struct tty_display_info *tty_out) #endif #endif -#ifdef F_SETFL -#ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */ +#ifdef F_GETOWN if (interrupt_input) { old_fcntl_owner[fileno (tty_out->input)] = @@ -1055,7 +1101,6 @@ init_sys_modes (struct tty_display_info *tty_out) #endif /* HAVE_GPM */ } #endif /* F_GETOWN */ -#endif /* F_SETFL */ #ifdef _IOFBF /* This symbol is defined on recent USG systems. @@ -1102,10 +1147,10 @@ init_sys_modes (struct tty_display_info *tty_out) tty_out->term_initted = 1; } -/* Return nonzero if safe to use tabs in output. +/* Return true if safe to use tabs in output. At the time this is called, init_sys_modes has not been done yet. */ -int +bool tabs_safe_p (int fd) { struct emacs_tty etty; @@ -1121,6 +1166,24 @@ tabs_safe_p (int fd) return 0; #endif /* DOS_NT */ } + +/* Discard echoing. */ + +void +suppress_echo_on_tty (int fd) +{ + struct emacs_tty etty; + + emacs_get_tty (fd, &etty); +#ifdef DOS_NT + /* Set raw input mode. */ + etty.main = 0; +#else + etty.main.c_lflag &= ~ICANON; /* Disable buffering */ + etty.main.c_lflag &= ~ECHO; /* Disable echoing */ +#endif /* ! WINDOWSNT */ + emacs_set_tty (fd, &etty, 0); +} /* Get terminal size from system. Store number of lines into *HEIGHTP and width into *WIDTHP. @@ -1180,7 +1243,8 @@ get_tty_size (int fd, int *widthp, int *heightp) } /* Set the logical window size associated with descriptor FD - to HEIGHT and WIDTH. This is used mainly with ptys. */ + to HEIGHT and WIDTH. This is used mainly with ptys. + Return a negative value on failure. */ int set_window_size (int fd, int height, int width) @@ -1192,10 +1256,7 @@ set_window_size (int fd, int height, int width) size.ws_row = height; size.ws_col = width; - if (ioctl (fd, TIOCSWINSZ, &size) == -1) - return 0; /* error */ - else - return 1; + return ioctl (fd, TIOCSWINSZ, &size); #else #ifdef TIOCSSIZE @@ -1205,10 +1266,7 @@ set_window_size (int fd, int height, int width) size.ts_lines = height; size.ts_cols = width; - if (ioctl (fd, TIOCGSIZE, &size) == -1) - return 0; - else - return 1; + return ioctl (fd, TIOCGSIZE, &size); #else return -1; #endif /* not SunOS-style */ @@ -1258,7 +1316,7 @@ reset_sys_modes (struct tty_display_info *tty_out) int i; tty_turn_off_insert (tty_out); - for (i = curX (tty_out); i < FrameCols (tty_out) - 1; i++) + for (i = cursorX (tty_out); i < FrameCols (tty_out) - 1; i++) { fputc (' ', tty_out->output); } @@ -1270,13 +1328,12 @@ reset_sys_modes (struct tty_display_info *tty_out) if (tty_out->terminal->reset_terminal_modes_hook) tty_out->terminal->reset_terminal_modes_hook (tty_out->terminal); -#ifdef BSD_SYSTEM /* Avoid possible loss of output when changing terminal modes. */ - fsync (fileno (tty_out->output)); -#endif + while (fdatasync (fileno (tty_out->output)) != 0 && errno == EINTR) + continue; -#ifdef F_SETFL -#ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */ +#ifndef DOS_NT +#ifdef F_SETOWN if (interrupt_input) { reset_sigio (fileno (tty_out->input)); @@ -1284,11 +1341,9 @@ reset_sys_modes (struct tty_display_info *tty_out) old_fcntl_owner[fileno (tty_out->input)]); } #endif /* F_SETOWN */ -#if O_NDELAY fcntl (fileno (tty_out->input), F_SETFL, - fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NDELAY); + fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NONBLOCK); #endif -#endif /* F_SETFL */ if (tty_out->old_tty) while (emacs_set_tty (fileno (tty_out->input), @@ -1362,8 +1417,10 @@ init_system_name (void) uname (&uts); Vsystem_name = build_string (uts.nodename); #else /* HAVE_GETHOSTNAME */ - unsigned int hostname_size = 256; - char *hostname = alloca (hostname_size); + char *hostname_alloc = NULL; + char hostname_buf[256]; + ptrdiff_t hostname_size = sizeof hostname_buf; + char *hostname = hostname_buf; /* Try to get the host name; if the buffer is too short, try again. Apparently, the only indication gethostname gives of @@ -1378,8 +1435,8 @@ init_system_name (void) if (strlen (hostname) < hostname_size - 1) break; - hostname_size <<= 1; - hostname = alloca (hostname_size); + hostname = hostname_alloc = xpalloc (hostname_alloc, &hostname_size, 1, + min (PTRDIFF_MAX, SIZE_MAX), 1); } #ifdef HAVE_SOCKETS /* Turn the hostname into the official, fully-qualified hostname. @@ -1424,7 +1481,13 @@ init_system_name (void) } if (it) { - hostname = alloca (strlen (it->ai_canonname) + 1); + ptrdiff_t len = strlen (it->ai_canonname); + if (hostname_size <= len) + { + hostname_size = len + 1; + hostname = hostname_alloc = xrealloc (hostname_alloc, + hostname_size); + } strcpy (hostname, it->ai_canonname); } freeaddrinfo (res); @@ -1471,10 +1534,11 @@ init_system_name (void) } #endif /* HAVE_SOCKETS */ Vsystem_name = build_string (hostname); + xfree (hostname_alloc); #endif /* HAVE_GETHOSTNAME */ { - unsigned char *p; - for (p = SDATA (Vsystem_name); *p; p++) + char *p; + for (p = SSDATA (Vsystem_name); *p; p++) if (*p == ' ' || *p == '\t') *p = '-'; } @@ -1534,9 +1598,6 @@ emacs_sigaction_init (struct sigaction *action, signal_handler_t handler) #endif } - if (! IEEE_FLOATING_POINT) - sigaddset (&action->sa_mask, SIGFPE); - action->sa_handler = handler; action->sa_flags = emacs_sigaction_flags (); } @@ -1616,6 +1677,8 @@ deliver_thread_signal (int sig, signal_handler_t handler) # undef sys_siglist # ifdef _sys_siglist # define sys_siglist _sys_siglist +# elif HAVE_DECL___SYS_SIGLIST +# define sys_siglist __sys_siglist # else # define sys_siglist my_sys_siglist static char const *sys_siglist[NSIG]; @@ -1660,6 +1723,25 @@ deliver_arith_signal (int sig) deliver_thread_signal (sig, handle_arith_signal); } +#ifdef SIGDANGER + +/* Handler for SIGDANGER. */ +static void +handle_danger_signal (int sig) +{ + malloc_warning ("Operating system warns that virtual memory is running low.\n"); + + /* It might be unsafe to call do_auto_save now. */ + force_auto_save_soon (); +} + +static void +deliver_danger_signal (int sig) +{ + deliver_process_signal (sig, handle_danger_signal); +} +#endif + /* Treat SIG as a terminating signal, unless it is already ignored and we are in --batch mode. Among other things, this makes nohup work. */ static void @@ -1695,15 +1777,10 @@ init_signals (bool dumping) # ifdef SIGAIO sys_siglist[SIGAIO] = "LAN I/O interrupt"; # endif -# ifdef SIGALRM sys_siglist[SIGALRM] = "Alarm clock"; -# endif # ifdef SIGBUS sys_siglist[SIGBUS] = "Bus error"; # endif -# ifdef SIGCLD - sys_siglist[SIGCLD] = "Child status changed"; -# endif # ifdef SIGCHLD sys_siglist[SIGCHLD] = "Child status changed"; # endif @@ -1726,9 +1803,7 @@ init_signals (bool dumping) # ifdef SIGGRANT sys_siglist[SIGGRANT] = "Monitor mode granted"; # endif -# ifdef SIGHUP sys_siglist[SIGHUP] = "Hangup"; -# endif sys_siglist[SIGILL] = "Illegal instruction"; sys_siglist[SIGINT] = "Interrupt"; # ifdef SIGIO @@ -1740,9 +1815,7 @@ init_signals (bool dumping) # ifdef SIGIOT sys_siglist[SIGIOT] = "IOT trap"; # endif -# ifdef SIGKILL sys_siglist[SIGKILL] = "Killed"; -# endif # ifdef SIGLOST sys_siglist[SIGLOST] = "Resource lost"; # endif @@ -1755,9 +1828,7 @@ init_signals (bool dumping) # ifdef SIGPHONE sys_siglist[SIGWIND] = "SIGPHONE"; # endif -# ifdef SIGPIPE sys_siglist[SIGPIPE] = "Broken pipe"; -# endif # ifdef SIGPOLL sys_siglist[SIGPOLL] = "Pollable event occurred"; # endif @@ -1770,9 +1841,7 @@ init_signals (bool dumping) # ifdef SIGPWR sys_siglist[SIGPWR] = "Power-fail restart"; # endif -# ifdef SIGQUIT sys_siglist[SIGQUIT] = "Quit"; -# endif # ifdef SIGRETRACT sys_siglist[SIGRETRACT] = "Need to relinquish monitor mode"; # endif @@ -2026,8 +2095,8 @@ seed_random (void *seed, ptrdiff_t seed_size) void init_random (void) { - EMACS_TIME t = current_emacs_time (); - uintmax_t v = getpid () ^ EMACS_SECS (t) ^ EMACS_NSECS (t); + struct timespec t = current_timespec (); + uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec; seed_random (&v, sizeof v); } @@ -2116,10 +2185,10 @@ emacs_backtrace (int backtrace_limit) if (npointers) { - ignore_value (write (STDERR_FILENO, "\nBacktrace:\n", 12)); + emacs_write (STDERR_FILENO, "\nBacktrace:\n", 12); backtrace_symbols_fd (buffer, npointers, STDERR_FILENO); if (bounded_limit < npointers) - ignore_value (write (STDERR_FILENO, "...\n", 4)); + emacs_write (STDERR_FILENO, "...\n", 4); } } @@ -2127,38 +2196,130 @@ emacs_backtrace (int backtrace_limit) void emacs_abort (void) { - terminate_due_to_signal (SIGABRT, 10); + terminate_due_to_signal (SIGABRT, 40); } #endif +/* Open FILE for Emacs use, using open flags OFLAG and mode MODE. + Arrange for subprograms to not inherit the file descriptor. + Prefer a method that is multithread-safe, if available. + Do not fail merely because the open was interrupted by a signal. + Allow the user to quit. */ + int -emacs_open (const char *path, int oflag, int mode) +emacs_open (const char *file, int oflags, int mode) { - register int rtnval; - - while ((rtnval = open (path, oflag, mode)) == -1 - && (errno == EINTR)) + int fd; + oflags |= O_CLOEXEC; + while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR) QUIT; - return (rtnval); + if (! O_CLOEXEC && 0 <= fd) + fcntl (fd, F_SETFD, FD_CLOEXEC); + return fd; } +/* Open FILE as a stream for Emacs use, with mode MODE. + Act like emacs_open with respect to threads, signals, and quits. */ + +FILE * +emacs_fopen (char const *file, char const *mode) +{ + int fd, omode, oflags; + int bflag = 0; + char const *m = mode; + + switch (*m++) + { + case 'r': omode = O_RDONLY; oflags = 0; break; + case 'w': omode = O_WRONLY; oflags = O_CREAT | O_TRUNC; break; + case 'a': omode = O_WRONLY; oflags = O_CREAT | O_APPEND; break; + default: emacs_abort (); + } + + while (*m) + switch (*m++) + { + case '+': omode = O_RDWR; break; + case 'b': bflag = O_BINARY; break; + case 't': bflag = O_TEXT; break; + default: /* Ignore. */ break; + } + + fd = emacs_open (file, omode | oflags | bflag, 0666); + return fd < 0 ? 0 : fdopen (fd, mode); +} + +/* Create a pipe for Emacs use. */ + int -emacs_close (int fd) +emacs_pipe (int fd[2]) { - int did_retry = 0; - register int rtnval; +#ifdef MSDOS + return pipe (fd); +#else /* !MSDOS */ + int result = pipe2 (fd, O_CLOEXEC); + if (! O_CLOEXEC && result == 0) + { + fcntl (fd[0], F_SETFD, FD_CLOEXEC); + fcntl (fd[1], F_SETFD, FD_CLOEXEC); + } + return result; +#endif /* !MSDOS */ +} - while ((rtnval = close (fd)) == -1 - && (errno == EINTR)) - did_retry = 1; +/* Approximate posix_close and POSIX_CLOSE_RESTART well enough for Emacs. + For the background behind this mess, please see Austin Group defect 529 + . */ + +#ifndef POSIX_CLOSE_RESTART +# define POSIX_CLOSE_RESTART 1 +static int +posix_close (int fd, int flag) +{ + /* Only the POSIX_CLOSE_RESTART case is emulated. */ + eassert (flag == POSIX_CLOSE_RESTART); + + /* Things are tricky if close (fd) returns -1 with errno == EINTR + on a system that does not define POSIX_CLOSE_RESTART. + + In this case, in some systems (e.g., GNU/Linux, AIX) FD is + closed, and retrying the close could inadvertently close a file + descriptor allocated by some other thread. In other systems + (e.g., HP/UX) FD is not closed. And in still other systems + (e.g., OS X, Solaris), maybe FD is closed, maybe not, and in a + multithreaded program there can be no way to tell. + + So, in this case, pretend that the close succeeded. This works + well on systems like GNU/Linux that close FD. Although it may + leak a file descriptor on other systems, the leak is unlikely and + it's better to leak than to close a random victim. */ + return close (fd) == 0 || errno == EINTR ? 0 : -1; +} +#endif + +/* Close FD, retrying if interrupted. If successful, return 0; + otherwise, return -1 and set errno to a non-EINTR value. Consider + an EINPROGRESS error to be successful, as that's merely a signal + arriving. FD is always closed when this function returns, even + when it returns -1. - /* If close is interrupted SunOS 4.1 may or may not have closed the - file descriptor. If it did the second close will fail with - errno = EBADF. That means we have succeeded. */ - if (rtnval == -1 && did_retry && errno == EBADF) - return 0; + Do not call this function if FD is nonnegative and might already be closed, + as that might close an innocent victim opened by some other thread. */ - return rtnval; +int +emacs_close (int fd) +{ + while (1) + { + int r = posix_close (fd, POSIX_CLOSE_RESTART); + if (r == 0) + return r; + if (!POSIX_CLOSE_RESTART || errno != EINTR) + { + eassert (errno != EBADF || fd < 0); + return errno == EINPROGRESS ? 0 : r; + } + } } /* Maximum number of bytes to read or write in a single system call. @@ -2176,9 +2337,9 @@ emacs_close (int fd) Return the number of bytes read, which might be less than NBYTE. On error, set errno and return -1. */ ptrdiff_t -emacs_read (int fildes, char *buf, ptrdiff_t nbyte) +emacs_read (int fildes, void *buf, ptrdiff_t nbyte) { - register ssize_t rtnval; + ssize_t rtnval; /* There is no need to check against MAX_RW_COUNT, since no caller ever passes a size that large to emacs_read. */ @@ -2190,27 +2351,26 @@ emacs_read (int fildes, char *buf, ptrdiff_t nbyte) } /* Write to FILEDES from a buffer BUF with size NBYTE, retrying if interrupted - or if a partial write occurs. Return the number of bytes written, setting + or if a partial write occurs. If interrupted, process pending + signals if PROCESS SIGNALS. Return the number of bytes written, setting errno if this is less than NBYTE. */ -ptrdiff_t -emacs_write (int fildes, const char *buf, ptrdiff_t nbyte) +static ptrdiff_t +emacs_full_write (int fildes, char const *buf, ptrdiff_t nbyte, + bool process_signals) { - ssize_t rtnval; - ptrdiff_t bytes_written; - - bytes_written = 0; + ptrdiff_t bytes_written = 0; while (nbyte > 0) { - rtnval = write (fildes, buf, min (nbyte, MAX_RW_COUNT)); + ssize_t n = write (fildes, buf, min (nbyte, MAX_RW_COUNT)); - if (rtnval < 0) + if (n < 0) { if (errno == EINTR) { /* I originally used `QUIT' but that might causes files to be truncated if you hit C-g in the middle of it. --Stef */ - if (pending_signals) + if (process_signals && pending_signals) process_pending_signals (); continue; } @@ -2218,111 +2378,64 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte) break; } - buf += rtnval; - nbyte -= rtnval; - bytes_written += rtnval; + buf += n; + nbyte -= n; + bytes_written += n; } - return (bytes_written); + return bytes_written; } -static struct allocator const emacs_norealloc_allocator = - { xmalloc, NULL, xfree, memory_full }; - -/* Get the symbolic link value of FILENAME. Return a pointer to a - NUL-terminated string. If readlink fails, return NULL and set - errno. If the value fits in INITIAL_BUF, return INITIAL_BUF. - Otherwise, allocate memory and return a pointer to that memory. If - memory allocation fails, diagnose and fail without returning. If - successful, store the length of the symbolic link into *LINKLEN. */ -char * -emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE]) +/* Write to FILEDES from a buffer BUF with size NBYTE, retrying if + interrupted or if a partial write occurs. Return the number of + bytes written, setting errno if this is less than NBYTE. */ +ptrdiff_t +emacs_write (int fildes, void const *buf, ptrdiff_t nbyte) { - return careadlinkat (AT_FDCWD, filename, initial_buf, READLINK_BUFSIZE, - &emacs_norealloc_allocator, careadlinkatcwd); + return emacs_full_write (fildes, buf, nbyte, 0); } - -#ifdef USG -/* - * All of the following are for USG. - * - * On USG systems the system calls are INTERRUPTIBLE by signals - * that the user program has elected to catch. Thus the system call - * must be retried in these cases. To handle this without massive - * changes in the source code, we remap the standard system call names - * to names for our own functions in sysdep.c that do the system call - * with retries. Actually, for portability reasons, it is good - * programming practice, as this example shows, to limit all actual - * system calls to a single occurrence in the source. Sure, this - * adds an extra level of function call overhead but it is almost - * always negligible. Fred Fish, Unisoft Systems Inc. - */ - -/* - * Warning, this function may not duplicate 4.2 action properly - * under error conditions. - */ -#if !defined (HAVE_GETWD) || defined (BROKEN_GETWD) - -#ifndef MAXPATHLEN -/* In 4.1, param.h fails to define this. */ -#define MAXPATHLEN 1024 -#endif - -char * -getwd (char *pathname) +/* Like emacs_write, but also process pending signals if interrupted. */ +ptrdiff_t +emacs_write_sig (int fildes, void const *buf, ptrdiff_t nbyte) { - char *npath, *spath; - extern char *getcwd (char *, size_t); + return emacs_full_write (fildes, buf, nbyte, 1); +} - block_input (); /* getcwd uses malloc */ - spath = npath = getcwd ((char *) 0, MAXPATHLEN); - if (spath == 0) +/* Write a diagnostic to standard error that contains MESSAGE and a + string derived from errno. Preserve errno. Do not buffer stderr. + Do not process pending signals if interrupted. */ +void +emacs_perror (char const *message) +{ + int err = errno; + char const *error_string = strerror (err); + char const *command = (initial_argv && initial_argv[0] + ? initial_argv[0] : "emacs"); + /* Write it out all at once, if it's short; this is less likely to + be interleaved with other output. */ + char buf[BUFSIZ]; + int nbytes = snprintf (buf, sizeof buf, "%s: %s: %s\n", + command, message, error_string); + if (0 <= nbytes && nbytes < BUFSIZ) + emacs_write (STDERR_FILENO, buf, nbytes); + else { - unblock_input (); - return spath; + emacs_write (STDERR_FILENO, command, strlen (command)); + emacs_write (STDERR_FILENO, ": ", 2); + emacs_write (STDERR_FILENO, message, strlen (message)); + emacs_write (STDERR_FILENO, ": ", 2); + emacs_write (STDERR_FILENO, error_string, strlen (error_string)); + emacs_write (STDERR_FILENO, "\n", 1); } - /* On Altos 3068, getcwd can return @hostname/dir, so discard - up to first slash. Should be harmless on other systems. */ - while (*npath && *npath != '/') - npath++; - strcpy (pathname, npath); - free (spath); /* getcwd uses malloc */ - unblock_input (); - return pathname; + errno = err; } - -#endif /* !defined (HAVE_GETWD) || defined (BROKEN_GETWD) */ -#endif /* USG */ - -/* Directory routines for systems that don't have them. */ - -#ifdef HAVE_DIRENT_H - -#include - -#if !defined (HAVE_CLOSEDIR) - -int -closedir (DIR *dirp /* stream from opendir */) -{ - int rtnval; - - rtnval = emacs_close (dirp->dd_fd); - xfree (dirp); - - return rtnval; -} -#endif /* not HAVE_CLOSEDIR */ -#endif /* HAVE_DIRENT_H */ - /* Return a struct timeval that is roughly equivalent to T. Use the least timeval not less than T. Return an extremal value if the result would overflow. */ struct timeval -make_timeval (EMACS_TIME t) +make_timeval (struct timespec t) { struct timeval tv; tv.tv_sec = t.tv_sec; @@ -2349,7 +2462,7 @@ make_timeval (EMACS_TIME t) If FD is nonnegative, then FILE can be NULL. */ int set_file_times (int fd, const char *filename, - EMACS_TIME atime, EMACS_TIME mtime) + struct timespec atime, struct timespec mtime) { struct timespec timespec[2]; timespec[0] = atime; @@ -2375,26 +2488,11 @@ safe_strsignal (int code) #ifndef DOS_NT /* For make-serial-process */ int -serial_open (char *port) +serial_open (Lisp_Object port) { - int fd = -1; - - fd = emacs_open ((char*) port, - O_RDWR -#if O_NONBLOCK - | O_NONBLOCK -#else - | O_NDELAY -#endif -#if O_NOCTTY - | O_NOCTTY -#endif - , 0); + int fd = emacs_open (SSDATA (port), O_RDWR | O_NOCTTY | O_NONBLOCK, 0); if (fd < 0) - { - error ("Could not open %s: %s", - port, emacs_strerror (errno)); - } + report_file_error ("Opening serial port", port); #ifdef TIOCEXCL ioctl (fd, TIOCEXCL, (char *) 0); #endif @@ -2434,7 +2532,7 @@ serial_configure (struct Lisp_Process *p, Lisp_Object childp2 = Qnil; Lisp_Object tem = Qnil; struct termios attr; - int err = -1; + int err; char summary[4] = "???"; /* This usually becomes "8N1". */ childp2 = Fcopy_sequence (p->childp); @@ -2442,7 +2540,7 @@ serial_configure (struct Lisp_Process *p, /* Read port attributes and prepare default configuration. */ err = tcgetattr (p->outfd, &attr); if (err != 0) - error ("tcgetattr() failed: %s", emacs_strerror (errno)); + report_file_error ("Failed tcgetattr", Qnil); cfmakeraw (&attr); #if defined (CLOCAL) attr.c_cflag |= CLOCAL; @@ -2459,8 +2557,7 @@ serial_configure (struct Lisp_Process *p, CHECK_NUMBER (tem); err = cfsetspeed (&attr, XINT (tem)); if (err != 0) - error ("cfsetspeed(%"pI"d) failed: %s", XINT (tem), - emacs_strerror (errno)); + report_file_error ("Failed cfsetspeed", tem); childp2 = Fplist_put (childp2, QCspeed, tem); /* Configure bytesize. */ @@ -2582,7 +2679,7 @@ serial_configure (struct Lisp_Process *p, /* Activate configuration. */ err = tcsetattr (p->outfd, TCSANOW, &attr); if (err != 0) - error ("tcsetattr() failed: %s", emacs_strerror (errno)); + report_file_error ("Failed tcsetattr", Qnil); childp2 = Fplist_put (childp2, QCsummary, build_string (summary)); pset_childp (p, childp2); @@ -2625,12 +2722,12 @@ list_system_processes (void) return proclist; } -#elif defined BSD_SYSTEM +#elif defined DARWIN_OS || defined __FreeBSD__ Lisp_Object list_system_processes (void) { -#if defined DARWIN_OS || defined __NetBSD__ || defined __OpenBSD__ +#ifdef DARWIN_OS int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; #else int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PROC}; @@ -2656,10 +2753,8 @@ list_system_processes (void) len /= sizeof (struct kinfo_proc); for (i = 0; i < len; i++) { -#if defined DARWIN_OS || defined __NetBSD__ +#ifdef DARWIN_OS proclist = Fcons (make_fixnum_or_float (procs[i].kp_proc.p_pid), proclist); -#elif defined __OpenBSD__ - proclist = Fcons (make_fixnum_or_float (procs[i].p_pid), proclist); #else proclist = Fcons (make_fixnum_or_float (procs[i].ki_pid), proclist); #endif @@ -2683,8 +2778,8 @@ list_system_processes (void) #endif /* !defined (WINDOWSNT) */ -#ifdef GNU_LINUX -static EMACS_TIME +#if defined GNU_LINUX && defined HAVE_LONG_LONG_INT +static struct timespec time_from_jiffies (unsigned long long tval, long hz) { unsigned long long s = tval / hz; @@ -2693,37 +2788,37 @@ time_from_jiffies (unsigned long long tval, long hz) if (TYPE_MAXIMUM (time_t) < s) time_overflow (); - if (LONG_MAX - 1 <= ULLONG_MAX / EMACS_TIME_RESOLUTION - || frac <= ULLONG_MAX / EMACS_TIME_RESOLUTION) - ns = frac * EMACS_TIME_RESOLUTION / hz; + if (LONG_MAX - 1 <= ULLONG_MAX / TIMESPEC_RESOLUTION + || frac <= ULLONG_MAX / TIMESPEC_RESOLUTION) + ns = frac * TIMESPEC_RESOLUTION / hz; else { /* This is reachable only in the unlikely case that HZ * HZ exceeds ULLONG_MAX. It calculates an approximation that is guaranteed to be in range. */ - long hz_per_ns = (hz / EMACS_TIME_RESOLUTION - + (hz % EMACS_TIME_RESOLUTION != 0)); + long hz_per_ns = (hz / TIMESPEC_RESOLUTION + + (hz % TIMESPEC_RESOLUTION != 0)); ns = frac / hz_per_ns; } - return make_emacs_time (s, ns); + return make_timespec (s, ns); } static Lisp_Object ltime_from_jiffies (unsigned long long tval, long hz) { - EMACS_TIME t = time_from_jiffies (tval, hz); + struct timespec t = time_from_jiffies (tval, hz); return make_lisp_time (t); } -static EMACS_TIME +static struct timespec get_up_time (void) { FILE *fup; - EMACS_TIME up = make_emacs_time (0, 0); + struct timespec up = make_timespec (0, 0); block_input (); - fup = fopen ("/proc/uptime", "r"); + fup = emacs_fopen ("/proc/uptime", "r"); if (fup) { @@ -2738,18 +2833,18 @@ get_up_time (void) if (TYPE_MAXIMUM (time_t) < upsec) { upsec = TYPE_MAXIMUM (time_t); - upfrac = EMACS_TIME_RESOLUTION - 1; + upfrac = TIMESPEC_RESOLUTION - 1; } else { int upfraclen = upfrac_end - upfrac_start; - for (; upfraclen < LOG10_EMACS_TIME_RESOLUTION; upfraclen++) + for (; upfraclen < LOG10_TIMESPEC_RESOLUTION; upfraclen++) upfrac *= 10; - for (; LOG10_EMACS_TIME_RESOLUTION < upfraclen; upfraclen--) + for (; LOG10_TIMESPEC_RESOLUTION < upfraclen; upfraclen--) upfrac /= 10; - upfrac = min (upfrac, EMACS_TIME_RESOLUTION - 1); + upfrac = min (upfrac, TIMESPEC_RESOLUTION - 1); } - up = make_emacs_time (upsec, upfrac); + up = make_timespec (upsec, upfrac); } fclose (fup); } @@ -2764,11 +2859,12 @@ get_up_time (void) static Lisp_Object procfs_ttyname (int rdev) { - FILE *fdev = NULL; + FILE *fdev; char name[PATH_MAX]; block_input (); - fdev = fopen ("/proc/tty/drivers", "r"); + fdev = emacs_fopen ("/proc/tty/drivers", "r"); + name[0] = 0; if (fdev) { @@ -2777,9 +2873,9 @@ procfs_ttyname (int rdev) char minor[25]; /* 2 32-bit numbers + dash */ char *endp; - while (!feof (fdev) && !ferror (fdev)) + for (; !feof (fdev) && !ferror (fdev); name[0] = 0) { - if (3 <= fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor) + if (fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor) >= 3 && major == MAJOR (rdev)) { minor_beg = strtoul (minor, &endp, 0); @@ -2803,29 +2899,41 @@ procfs_ttyname (int rdev) return build_string (name); } -static unsigned long +static uintmax_t procfs_get_total_memory (void) { - FILE *fmem = NULL; - unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */ + FILE *fmem; + uintmax_t retval = 2 * 1024 * 1024; /* default: 2 GiB */ + int c; block_input (); - fmem = fopen ("/proc/meminfo", "r"); + fmem = emacs_fopen ("/proc/meminfo", "r"); if (fmem) { - unsigned long entry_value; - char entry_name[20]; /* the longest I saw is 13+1 */ + uintmax_t entry_value; + bool done; + + do + switch (fscanf (fmem, "MemTotal: %"SCNuMAX, &entry_value)) + { + case 1: + retval = entry_value; + done = 1; + break; + + case 0: + while ((c = getc (fmem)) != EOF && c != '\n') + continue; + done = c == EOF; + break; + + default: + done = 1; + break; + } + while (!done); - while (!feof (fmem) && !ferror (fmem)) - { - if (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value) - && strcmp (entry_name, "MemTotal:") == 0) - { - retval = entry_value; - break; - } - } fclose (fmem); } unblock_input (); @@ -2849,7 +2957,7 @@ system_process_attributes (Lisp_Object pid) int cmdsize = sizeof default_cmd - 1; char *cmdline = NULL; ptrdiff_t cmdline_size; - unsigned char c; + char c; printmax_t proc_id; int ppid, pgrp, sess, tty, tpgid, thcount; uid_t uid; @@ -2857,10 +2965,11 @@ system_process_attributes (Lisp_Object pid) unsigned long long u_time, s_time, cutime, cstime, start; long priority, niceness, rss; unsigned long minflt, majflt, cminflt, cmajflt, vsize; - EMACS_TIME tnow, tstart, tboot, telapsed, us_time; + struct timespec tnow, tstart, tboot, telapsed, us_time; double pcpu, pmem; Lisp_Object attrs = Qnil; - Lisp_Object cmd_str, decoded_cmd, tem; + Lisp_Object cmd_str, decoded_cmd; + ptrdiff_t count; struct gcpro gcpro1, gcpro2; CHECK_NUMBER_OR_FLOAT (pid); @@ -2888,11 +2997,19 @@ system_process_attributes (Lisp_Object pid) if (gr) attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); + count = SPECPDL_INDEX (); strcpy (fn, procfn); procfn_end = fn + strlen (fn); strcpy (procfn_end, "/stat"); fd = emacs_open (fn, O_RDONLY, 0); - if (fd >= 0 && (nread = emacs_read (fd, procbuf, sizeof (procbuf) - 1)) > 0) + if (fd < 0) + nread = 0; + else + { + record_unwind_protect_int (close_file_unwind, fd); + nread = emacs_read (fd, procbuf, sizeof procbuf - 1); + } + if (0 < nread) { procbuf[nread] = '\0'; p = procbuf; @@ -2916,39 +3033,32 @@ system_process_attributes (Lisp_Object pid) Vlocale_coding_system, 0); attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs); - if (q) + /* state ppid pgrp sess tty tpgid . minflt cminflt majflt cmajflt + utime stime cutime cstime priority nice thcount . start vsize rss */ + if (q + && (sscanf (q + 2, ("%c %d %d %d %d %d %*u %lu %lu %lu %lu " + "%Lu %Lu %Lu %Lu %ld %ld %d %*d %Lu %lu %ld"), + &c, &ppid, &pgrp, &sess, &tty, &tpgid, + &minflt, &cminflt, &majflt, &cmajflt, + &u_time, &s_time, &cutime, &cstime, + &priority, &niceness, &thcount, &start, &vsize, &rss) + == 20)) { - EMACS_INT ppid_eint, pgrp_eint, sess_eint, tpgid_eint, thcount_eint; - p = q + 2; - /* state ppid pgrp sess tty tpgid . minflt cminflt majflt cmajflt utime stime cutime cstime priority nice thcount . start vsize rss */ - sscanf (p, "%c %d %d %d %d %d %*u %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld %d %*d %Lu %lu %ld", - &c, &ppid, &pgrp, &sess, &tty, &tpgid, - &minflt, &cminflt, &majflt, &cmajflt, - &u_time, &s_time, &cutime, &cstime, - &priority, &niceness, &thcount, &start, &vsize, &rss); - { - char state_str[2]; - - state_str[0] = c; - state_str[1] = '\0'; - tem = build_string (state_str); - attrs = Fcons (Fcons (Qstate, tem), attrs); - } - /* Stops GCC whining about limited range of data type. */ - ppid_eint = ppid; - pgrp_eint = pgrp; - sess_eint = sess; - tpgid_eint = tpgid; - thcount_eint = thcount; - attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (ppid_eint)), attrs); - attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pgrp_eint)), attrs); - attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (sess_eint)), attrs); + char state_str[2]; + state_str[0] = c; + state_str[1] = '\0'; + attrs = Fcons (Fcons (Qstate, build_string (state_str)), attrs); + attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (ppid)), attrs); + attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pgrp)), attrs); + attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (sess)), attrs); attrs = Fcons (Fcons (Qttname, procfs_ttyname (tty)), attrs); - attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (tpgid_eint)), attrs); + attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (tpgid)), attrs); attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (minflt)), attrs); attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (majflt)), attrs); - attrs = Fcons (Fcons (Qcminflt, make_fixnum_or_float (cminflt)), attrs); - attrs = Fcons (Fcons (Qcmajflt, make_fixnum_or_float (cmajflt)), attrs); + attrs = Fcons (Fcons (Qcminflt, make_fixnum_or_float (cminflt)), + attrs); + attrs = Fcons (Fcons (Qcmajflt, make_fixnum_or_float (cmajflt)), + attrs); clocks_per_sec = sysconf (_SC_CLK_TCK); if (clocks_per_sec < 0) clocks_per_sec = 100; @@ -2969,24 +3079,26 @@ system_process_attributes (Lisp_Object pid) ltime_from_jiffies (cstime, clocks_per_sec)), attrs); attrs = Fcons (Fcons (Qctime, - ltime_from_jiffies (cstime+cutime, clocks_per_sec)), + ltime_from_jiffies (cstime + cutime, + clocks_per_sec)), attrs); attrs = Fcons (Fcons (Qpri, make_number (priority)), attrs); attrs = Fcons (Fcons (Qnice, make_number (niceness)), attrs); - attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs); - tnow = current_emacs_time (); + attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount)), + attrs); + tnow = current_timespec (); telapsed = get_up_time (); - tboot = sub_emacs_time (tnow, telapsed); + tboot = timespec_sub (tnow, telapsed); tstart = time_from_jiffies (start, clocks_per_sec); - tstart = add_emacs_time (tboot, tstart); + tstart = timespec_add (tboot, tstart); attrs = Fcons (Fcons (Qstart, make_lisp_time (tstart)), attrs); - attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs); - attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs); - telapsed = sub_emacs_time (tnow, tstart); + attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize / 1024)), + attrs); + attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4 * rss)), attrs); + telapsed = timespec_sub (tnow, tstart); attrs = Fcons (Fcons (Qetime, make_lisp_time (telapsed)), attrs); us_time = time_from_jiffies (u_time + s_time, clocks_per_sec); - pcpu = (EMACS_TIME_TO_DOUBLE (us_time) - / EMACS_TIME_TO_DOUBLE (telapsed)); + pcpu = timespectod (us_time) / timespectod (telapsed); if (pcpu > 1.0) pcpu = 1.0; attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); @@ -2996,67 +3108,63 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs); } } - if (fd >= 0) - emacs_close (fd); + unbind_to (count, Qnil); /* args */ strcpy (procfn_end, "/cmdline"); fd = emacs_open (fn, O_RDONLY, 0); if (fd >= 0) { - char ch; - for (cmdline_size = 0; cmdline_size < STRING_BYTES_BOUND; cmdline_size++) + ptrdiff_t readsize, nread_incr; + record_unwind_protect_int (close_file_unwind, fd); + record_unwind_protect_nothing (); + nread = cmdline_size = 0; + + do { - if (emacs_read (fd, &ch, 1) != 1) - break; - c = ch; - if (c_isspace (c) || c == '\\') - cmdline_size++; /* for later quoting, see below */ + cmdline = xpalloc (cmdline, &cmdline_size, 2, STRING_BYTES_BOUND, 1); + set_unwind_protect_ptr (count + 1, xfree, cmdline); + + /* Leave room even if every byte needs escaping below. */ + readsize = (cmdline_size >> 1) - nread; + + nread_incr = emacs_read (fd, cmdline + nread, readsize); + nread += max (0, nread_incr); } - if (cmdline_size) + while (nread_incr == readsize); + + if (nread) { - cmdline = xmalloc (cmdline_size + 1); - lseek (fd, 0L, SEEK_SET); - cmdline[0] = '\0'; - if ((nread = read (fd, cmdline, cmdline_size)) >= 0) - cmdline[nread++] = '\0'; - else - { - /* Assigning zero to `nread' makes us skip the following - two loops, assign zero to cmdline_size, and enter the - following `if' clause that handles unknown command - lines. */ - nread = 0; - } /* We don't want trailing null characters. */ - for (p = cmdline + nread; p > cmdline + 1 && !p[-1]; p--) - nread--; - for (p = cmdline; p < cmdline + nread; p++) + for (p = cmdline + nread; cmdline < p && !p[-1]; p--) + continue; + + /* Escape-quote whitespace and backslashes. */ + q = cmdline + cmdline_size; + while (cmdline < p) { - /* Escape-quote whitespace and backslashes. */ - if (c_isspace (*p) || *p == '\\') - { - memmove (p + 1, p, nread - (p - cmdline)); - nread++; - *p++ = '\\'; - } - else if (*p == '\0') - *p = ' '; + char c = *--p; + *--q = c ? c : ' '; + if (c_isspace (c) || c == '\\') + *--q = '\\'; } - cmdline_size = nread; + + nread = cmdline + cmdline_size - q; } - if (!cmdline_size) + + if (!nread) { - cmdline_size = cmdsize + 2; - cmdline = xmalloc (cmdline_size + 1); + nread = cmdsize + 2; + cmdline_size = nread + 1; + q = cmdline = xrealloc (cmdline, cmdline_size); + set_unwind_protect_ptr (count + 1, xfree, cmdline); sprintf (cmdline, "[%.*s]", cmdsize, cmd); } - emacs_close (fd); /* Command line is encoded in locale-coding-system; decode it. */ - cmd_str = make_unibyte_string (cmdline, cmdline_size); + cmd_str = make_unibyte_string (q, nread); decoded_cmd = code_convert_string_norecord (cmd_str, Vlocale_coding_system, 0); - xfree (cmdline); + unbind_to (count, Qnil); attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); } @@ -3098,8 +3206,9 @@ system_process_attributes (Lisp_Object pid) uid_t uid; gid_t gid; Lisp_Object attrs = Qnil; - Lisp_Object decoded_cmd, tem; + Lisp_Object decoded_cmd; struct gcpro gcpro1, gcpro2; + ptrdiff_t count; CHECK_NUMBER_OR_FLOAT (pid); CONS_TO_INTEGER (pid, pid_t, proc_id); @@ -3126,88 +3235,97 @@ system_process_attributes (Lisp_Object pid) if (gr) attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); + count = SPECPDL_INDEX (); strcpy (fn, procfn); procfn_end = fn + strlen (fn); strcpy (procfn_end, "/psinfo"); fd = emacs_open (fn, O_RDONLY, 0); - if (fd >= 0 - && (nread = read (fd, (char*)&pinfo, sizeof (struct psinfo)) > 0)) + if (fd < 0) + nread = 0; + else { - attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (pinfo.pr_ppid)), attrs); - attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pinfo.pr_pgid)), attrs); - attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (pinfo.pr_sid)), attrs); - - { - char state_str[2]; - state_str[0] = pinfo.pr_lwp.pr_sname; - state_str[1] = '\0'; - tem = build_string (state_str); - attrs = Fcons (Fcons (Qstate, tem), attrs); - } - - /* FIXME: missing Qttyname. psinfo.pr_ttydev is a dev_t, - need to get a string from it. */ - - /* FIXME: missing: Qtpgid */ - - /* FIXME: missing: - Qminflt - Qmajflt - Qcminflt - Qcmajflt - - Qutime - Qcutime - Qstime - Qcstime - Are they available? */ - - attrs = Fcons (Fcons (Qtime, make_lisp_time (pinfo.pr_time)), attrs); - attrs = Fcons (Fcons (Qctime, make_lisp_time (pinfo.pr_ctime)), attrs); - attrs = Fcons (Fcons (Qpri, make_number (pinfo.pr_lwp.pr_pri)), attrs); - attrs = Fcons (Fcons (Qnice, make_number (pinfo.pr_lwp.pr_nice)), attrs); - attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (pinfo.pr_nlwp)), attrs); - - attrs = Fcons (Fcons (Qstart, make_lisp_time (pinfo.pr_start)), attrs); - attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (pinfo.pr_size)), attrs); - attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (pinfo.pr_rssize)), attrs); - - /* pr_pctcpu and pr_pctmem are unsigned integers in the - range 0 .. 2**15, representing 0.0 .. 1.0. */ - attrs = Fcons (Fcons (Qpcpu, make_float (100.0 / 0x8000 * pinfo.pr_pctcpu)), attrs); - attrs = Fcons (Fcons (Qpmem, make_float (100.0 / 0x8000 * pinfo.pr_pctmem)), attrs); - - decoded_cmd - = code_convert_string_norecord (make_unibyte_string (pinfo.pr_fname, - strlen (pinfo.pr_fname)), - Vlocale_coding_system, 0); - attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs); - decoded_cmd - = code_convert_string_norecord (make_unibyte_string (pinfo.pr_psargs, - strlen (pinfo.pr_psargs)), - Vlocale_coding_system, 0); - attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); + record_unwind_protect (close_file_unwind, fd); + nread = emacs_read (fd, &pinfo, sizeof pinfo); } - if (fd >= 0) - emacs_close (fd); + if (nread == sizeof pinfo) + { + attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (pinfo.pr_ppid)), attrs); + attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pinfo.pr_pgid)), attrs); + attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (pinfo.pr_sid)), attrs); + + { + char state_str[2]; + state_str[0] = pinfo.pr_lwp.pr_sname; + state_str[1] = '\0'; + attrs = Fcons (Fcons (Qstate, build_string (state_str)), attrs); + } + /* FIXME: missing Qttyname. psinfo.pr_ttydev is a dev_t, + need to get a string from it. */ + + /* FIXME: missing: Qtpgid */ + + /* FIXME: missing: + Qminflt + Qmajflt + Qcminflt + Qcmajflt + + Qutime + Qcutime + Qstime + Qcstime + Are they available? */ + + attrs = Fcons (Fcons (Qtime, make_lisp_time (pinfo.pr_time)), attrs); + attrs = Fcons (Fcons (Qctime, make_lisp_time (pinfo.pr_ctime)), attrs); + attrs = Fcons (Fcons (Qpri, make_number (pinfo.pr_lwp.pr_pri)), attrs); + attrs = Fcons (Fcons (Qnice, make_number (pinfo.pr_lwp.pr_nice)), attrs); + attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (pinfo.pr_nlwp)), + attrs); + + attrs = Fcons (Fcons (Qstart, make_lisp_time (pinfo.pr_start)), attrs); + attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (pinfo.pr_size)), + attrs); + attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (pinfo.pr_rssize)), + attrs); + + /* pr_pctcpu and pr_pctmem are unsigned integers in the + range 0 .. 2**15, representing 0.0 .. 1.0. */ + attrs = Fcons (Fcons (Qpcpu, + make_float (100.0 / 0x8000 * pinfo.pr_pctcpu)), + attrs); + attrs = Fcons (Fcons (Qpmem, + make_float (100.0 / 0x8000 * pinfo.pr_pctmem)), + attrs); + + decoded_cmd = (code_convert_string_norecord + (build_unibyte_string (pinfo.pr_fname), + Vlocale_coding_system, 0)); + attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs); + decoded_cmd = (code_convert_string_norecord + (build_unibyte_string (pinfo.pr_psargs), + Vlocale_coding_system, 0)); + attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); + } + unbind_to (count, Qnil); UNGCPRO; return attrs; } #elif defined __FreeBSD__ -static EMACS_TIME -timeval_to_EMACS_TIME (struct timeval t) +static struct timespec +timeval_to_timespec (struct timeval t) { - return make_emacs_time (t.tv_sec, t.tv_usec * 1000); + return make_timespec (t.tv_sec, t.tv_usec * 1000); } static Lisp_Object make_lisp_timeval (struct timeval t) { - return make_lisp_time (timeval_to_EMACS_TIME (t)); + return make_lisp_time (timeval_to_timespec (t)); } Lisp_Object @@ -3215,14 +3333,14 @@ system_process_attributes (Lisp_Object pid) { int proc_id; int pagesize = getpagesize (); - int npages; + unsigned long npages; int fscale; struct passwd *pw; struct group *gr; char *ttyname; size_t len; char args[MAXPATHLEN]; - EMACS_TIME t, now; + struct timespec t, now; int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID}; struct kinfo_proc proc; @@ -3257,9 +3375,9 @@ system_process_attributes (Lisp_Object pid) if (gr) attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); - decoded_comm = code_convert_string_norecord - (make_unibyte_string (proc.ki_comm, strlen (proc.ki_comm)), - Vlocale_coding_system, 0); + decoded_comm = (code_convert_string_norecord + (build_unibyte_string (proc.ki_comm), + Vlocale_coding_system, 0)); attrs = Fcons (Fcons (Qcomm, decoded_comm), attrs); { @@ -3309,8 +3427,8 @@ system_process_attributes (Lisp_Object pid) attrs); attrs = Fcons (Fcons (Qstime, make_lisp_timeval (proc.ki_rusage.ru_stime)), attrs); - t = add_emacs_time (timeval_to_EMACS_TIME (proc.ki_rusage.ru_utime), - timeval_to_EMACS_TIME (proc.ki_rusage.ru_stime)); + t = timespec_add (timeval_to_timespec (proc.ki_rusage.ru_utime), + timeval_to_timespec (proc.ki_rusage.ru_stime)); attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs); attrs = Fcons (Fcons (Qcutime, @@ -3319,8 +3437,8 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qcstime, make_lisp_timeval (proc.ki_rusage_ch.ru_utime)), attrs); - t = add_emacs_time (timeval_to_EMACS_TIME (proc.ki_rusage_ch.ru_utime), - timeval_to_EMACS_TIME (proc.ki_rusage_ch.ru_stime)); + t = timespec_add (timeval_to_timespec (proc.ki_rusage_ch.ru_utime), + timeval_to_timespec (proc.ki_rusage_ch.ru_stime)); attrs = Fcons (Fcons (Qctime, make_lisp_time (t)), attrs); attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (proc.ki_numthreads)), @@ -3332,8 +3450,8 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qrss, make_number (proc.ki_rssize * pagesize >> 10)), attrs); - now = current_emacs_time (); - t = sub_emacs_time (now, timeval_to_EMACS_TIME (proc.ki_start)); + now = current_timespec (); + t = timespec_sub (now, timeval_to_timespec (proc.ki_start)); attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs); len = sizeof fscale;