[TMP] enable load_prefer_newer
[bpt/emacs.git] / src / sysdep.c
index aa9d0f3..e8b0057 100644 (file)
@@ -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 <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
-#define SYSTIME_INLINE EXTERN_INLINE
-
 #include <execinfo.h>
-#include <stdio.h>
+#include "sysstdio.h"
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #include <grp.h>
@@ -30,25 +28,26 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <limits.h>
 #include <unistd.h>
 
-#include <allocator.h>
 #include <c-ctype.h>
-#include <careadlinkat.h>
-#include <ignore-value.h>
 #include <utimens.h>
 
 #include "lisp.h"
 #include "sysselect.h"
 #include "blockinput.h"
 
-#ifdef BSD_SYSTEM
-#include <sys/param.h>
-#include <sys/sysctl.h>
+#if defined DARWIN_OS || defined __FreeBSD__
+# include <sys/sysctl.h>
 #endif
 
 #ifdef __FreeBSD__
-#include <sys/user.h>
-#include <sys/resource.h>
-#include <math.h>
+/* Sparc/ARM machine/frame.h has 'struct frame' which conflicts with Emacs's
+   'struct frame', so rename it.  */
+# define frame freebsd_frame
+# include <sys/user.h>
+# undef frame
+
+# include <sys/resource.h>
+# include <math.h>
 #endif
 
 #ifdef WINDOWSNT
@@ -71,9 +70,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef MSDOS   /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
 #include "msdos.h"
-#include <sys/param.h>
 #endif
 
+#include <sys/param.h>
 #include <sys/file.h>
 #include <fcntl.h>
 
@@ -101,14 +100,13 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #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);
+static void emacs_get_tty (int, struct emacs_tty *);
+static int emacs_set_tty (int, struct emacs_tty *, bool);
 
 /* 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,60 +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)
-    {
-#ifdef WINDOWSNT
-      wait (0);
-      break;
-#else /* not WINDOWSNT */
-      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;
-       }
+  pid_t pid;
 
-#endif /* not WINDOWSNT */
+  /* 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)
+    {
+      /* 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);
 }
+
 \f
 /*  Set up the terminal at the other end of a pseudo-terminal that
     we will be controlling an inferior through.
@@ -449,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.  */
@@ -472,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;
@@ -491,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)
@@ -524,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");
@@ -554,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);
@@ -572,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 */
     }
@@ -581,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
@@ -614,7 +592,7 @@ restore_signal_handlers (struct save_signal *saved_handlers)
 }
 \f
 #ifdef USABLE_SIGIO
-static int old_fcntl_flags[MAXDESC];
+static int old_fcntl_flags[FD_SETSIZE];
 #endif
 
 void
@@ -627,6 +605,7 @@ init_sigio (int fd)
 #endif
 }
 
+#ifndef DOS_NT
 static void
 reset_sigio (int fd)
 {
@@ -634,6 +613,7 @@ reset_sigio (int fd)
   fcntl (fd, F_SETFL, old_fcntl_flags[fd]);
 #endif
 }
+#endif
 
 void
 request_sigio (void)
@@ -681,7 +661,29 @@ ignore_sigio (void)
   signal (SIGIO, SIG_IGN);
 #endif
 }
+\f
+#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 */
 \f
 /* Saving and restoring the process group of Emacs's terminal.  */
 
@@ -713,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
@@ -724,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
 }
@@ -754,31 +777,26 @@ widen_foreground_group (int fd)
 \f
 /* 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.  */
+static 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;
+  tcgetattr (fd, &settings->main);
 #endif
-
-  /* We have survived the tempest.  */
-  return 0;
 }
 
 
 /* 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)
+static int
+emacs_set_tty (int fd, struct emacs_tty *settings, bool flushp)
 {
   /* Set the primary parameters - baud rate, character size, etcetera.  */
 #ifndef DOS_NT
@@ -828,7 +846,7 @@ emacs_set_tty (int fd, struct emacs_tty *settings, int flushp)
 \f
 
 #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,
@@ -1039,8 +1057,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)] =
@@ -1058,7 +1075,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.
@@ -1105,10 +1121,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;
@@ -1183,7 +1199,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)
@@ -1195,10 +1212,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
@@ -1208,10 +1222,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 */
@@ -1261,7 +1272,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);
         }
@@ -1273,13 +1284,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));
@@ -1287,11 +1297,9 @@ reset_sys_modes (struct tty_display_info *tty_out)
              old_fcntl_owner[fileno (tty_out->input)]);
     }
 #endif /* F_SETOWN */
-#ifdef 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),
@@ -1365,8 +1373,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
@@ -1381,8 +1391,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.
@@ -1427,7 +1437,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);
@@ -1474,10 +1490,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 = '-';
   }
@@ -1537,9 +1554,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 ();
 }
@@ -1619,6 +1633,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];
@@ -1663,6 +1679,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
@@ -1698,15 +1733,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
@@ -1729,9 +1759,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
@@ -1743,9 +1771,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
@@ -1758,9 +1784,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
@@ -1773,9 +1797,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
@@ -1928,9 +1950,6 @@ init_signals (bool dumping)
 #ifdef SIGVTALRM
   sigaction (SIGVTALRM, &process_fatal_action, 0);
 #endif
-#ifdef SIGXCPU
-  sigaction (SIGXCPU, &process_fatal_action, 0);
-#endif
 #ifdef SIGXFSZ
   sigaction (SIGXFSZ, &process_fatal_action, 0);
 #endif
@@ -2029,8 +2048,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);
 }
 
@@ -2119,10 +2138,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);
     }
 }
 \f
@@ -2130,38 +2149,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
+   <http://austingroupbugs.net/view.php?id=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.
 
-  /* 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;
+     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.
 
-  return rtnval;
+     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.
+
+   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.  */
+
+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.
@@ -2179,9 +2290,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.  */
@@ -2193,27 +2304,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;
            }
@@ -2221,111 +2331,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);
 }
-\f
-#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;
-}
-
-#endif /* !defined (HAVE_GETWD) || defined (BROKEN_GETWD) */
-#endif /* USG */
-\f
-/* Directory routines for systems that don't have them. */
-
-#ifdef HAVE_DIRENT_H
-
-#include <dirent.h>
-
-#if !defined (HAVE_CLOSEDIR)
-
-int
-closedir (DIR *dirp /* stream from opendir */)
-{
-  int rtnval;
-
-  rtnval = emacs_close (dirp->dd_fd);
-  xfree (dirp);
-
-  return rtnval;
+  errno = err;
 }
-#endif /* not HAVE_CLOSEDIR */
-#endif /* HAVE_DIRENT_H */
-
 \f
 /* 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;
@@ -2352,7 +2415,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;
@@ -2378,26 +2441,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
-#ifdef O_NONBLOCK
-                  | O_NONBLOCK
-#else
-                  | O_NDELAY
-#endif
-#ifdef 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
@@ -2437,7 +2485,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);
@@ -2445,7 +2493,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;
@@ -2462,8 +2510,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.  */
@@ -2585,7 +2632,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);
@@ -2628,12 +2675,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};
@@ -2659,10 +2706,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
@@ -2686,8 +2731,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;
@@ -2696,37 +2741,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)
     {
@@ -2741,18 +2786,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);
     }
@@ -2767,11 +2812,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)
     {
@@ -2780,9 +2826,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);
@@ -2806,29 +2852,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 ();
@@ -2852,7 +2910,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;
@@ -2860,10 +2918,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);
@@ -2891,11 +2950,19 @@ system_process_attributes (Lisp_Object pid)
   if (gr)
     attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
 
+  dynwind_begin ();
   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;
@@ -2919,39 +2986,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;
@@ -2972,24 +3032,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);
@@ -2999,67 +3061,61 @@ system_process_attributes (Lisp_Object pid)
          attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs);
        }
     }
-  if (fd >= 0)
-    emacs_close (fd);
+  dynwind_end ();
 
   /* 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;
+      dynwind_begin ();
+      record_unwind_protect_int (close_file_unwind, fd);
+      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);
+
+         /* 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);
          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);
+      dynwind_end ();
       attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
     }
 
@@ -3101,8 +3157,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);
@@ -3129,88 +3186,97 @@ system_process_attributes (Lisp_Object pid)
   if (gr)
     attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
 
+  dynwind_begin ();
   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);
+    }
+  dynwind_end ();
   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
@@ -3218,14 +3284,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;
@@ -3260,9 +3326,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);
   {
@@ -3312,8 +3378,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,
@@ -3322,8 +3388,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)),
@@ -3335,8 +3401,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;