use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / sysdep.c
index 653cf22..e8b0057 100644 (file)
@@ -1,5 +1,5 @@
 /* Interfaces to system-dependent kernel and library entries.
-   Copyright (C) 1985-1988, 1993-1995, 1999-2013 Free Software
+   Copyright (C) 1985-1988, 1993-1995, 1999-2014 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -19,8 +19,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
-#define SYSTIME_INLINE EXTERN_INLINE
-
 #include <execinfo.h>
 #include "sysstdio.h"
 #ifdef HAVE_PWD_H
@@ -42,9 +40,14 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #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
@@ -125,7 +128,7 @@ 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;
@@ -219,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 */
@@ -252,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;
@@ -301,7 +306,7 @@ get_child_status (pid_t child, int *status, int options, bool interruptible)
   /* 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_emacs_time (0, 0);
+    *input_available_clear_time = make_timespec (0, 0);
 
   return pid;
 }
@@ -332,16 +337,6 @@ child_status_changed (pid_t child, int *status, int options)
   return get_child_status (child, status, WNOHANG | options, 0);
 }
 
-/*
- *     flush any pending output
- *      (may flush input as well; it does not matter the way we use it)
- */
-
-void
-flush_pending_output (int channel)
-{
-  /* FIXME: maybe this function should be removed */
-}
 \f
 /*  Set up the terminal at the other end of a pseudo-terminal that
     we will be controlling an inferior through.
@@ -471,15 +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
 #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,31 +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);
-#else
-  pid = vfork ();
-  if (pid == -1)
-    error ("Can't spawn subshell");
 #endif
 
   if (pid == 0)
@@ -533,11 +519,10 @@ sys_subshell (void)
        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
-         emacs_perror ((char *) str);
+         emacs_perror (str);
          _exit (EXIT_CANCELED);
 #endif
        }
@@ -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);
@@ -609,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
@@ -622,6 +605,7 @@ init_sigio (int fd)
 #endif
 }
 
+#ifndef DOS_NT
 static void
 reset_sigio (int fd)
 {
@@ -629,6 +613,7 @@ reset_sigio (int fd)
   fcntl (fd, F_SETFL, old_fcntl_flags[fd]);
 #endif
 }
+#endif
 
 void
 request_sigio (void)
@@ -676,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.  */
 
@@ -711,21 +718,21 @@ init_foreground_group (void)
 /* Block and unblock SIGTTOU.  */
 
 void
-block_tty_out_signal (void)
+block_tty_out_signal (sigset_t *oldset)
 {
 #ifdef SIGTTOU
   sigset_t blocked;
   sigemptyset (&blocked);
   sigaddset (&blocked, SIGTTOU);
-  pthread_sigmask (SIG_BLOCK, &blocked, 0);
+  pthread_sigmask (SIG_BLOCK, &blocked, oldset);
 #endif
 }
 
 void
-unblock_tty_out_signal (void)
+unblock_tty_out_signal (sigset_t const *oldset)
 {
 #ifdef SIGTTOU
-  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+  pthread_sigmask (SIG_SETMASK, oldset, 0);
 #endif
 }
 
@@ -740,10 +747,11 @@ static void
 tcsetpgrp_without_stopping (int fd, pid_t pgid)
 {
 #ifdef SIGTTOU
+  sigset_t oldset;
   block_input ();
-  block_tty_out_signal ();
+  block_tty_out_signal (&oldset);
   tcsetpgrp (fd, pgid);
-  unblock_tty_out_signal ();
+  unblock_tty_out_signal (&oldset);
   unblock_input ();
 #endif
 }
@@ -838,7 +846,7 @@ emacs_set_tty (int fd, struct emacs_tty *settings, bool 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,
@@ -1191,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)
@@ -1203,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
@@ -1216,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 */
@@ -1269,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);
         }
@@ -1530,7 +1533,9 @@ emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
   /* When handling a signal, block nonfatal system signals that are caught
      by Emacs.  This makes race conditions less likely.  */
   sigaddset (&action->sa_mask, SIGALRM);
+#ifdef SIGCHLD
   sigaddset (&action->sa_mask, SIGCHLD);
+#endif
 #ifdef SIGDANGER
   sigaddset (&action->sa_mask, SIGDANGER);
 #endif
@@ -1549,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 ();
 }
@@ -1735,7 +1737,9 @@ init_signals (bool dumping)
 # ifdef SIGBUS
       sys_siglist[SIGBUS] = "Bus error";
 # endif
+# ifdef SIGCHLD
       sys_siglist[SIGCHLD] = "Child status changed";
+# endif
 # ifdef SIGCONT
       sys_siglist[SIGCONT] = "Continued";
 # endif
@@ -1946,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
@@ -2047,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);
 }
 
@@ -2201,23 +2202,77 @@ emacs_fopen (char const *file, char const *mode)
   return fd < 0 ? 0 : fdopen (fd, mode);
 }
 
+/* Create a pipe for Emacs use.  */
+
 int
-emacs_close (int fd)
+emacs_pipe (int fd[2])
 {
-  bool did_retry = 0;
-  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);
 
-  /* 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;
+  /* Things are tricky if close (fd) returns -1 with errno == EINTR
+     on a system that does not define POSIX_CLOSE_RESTART.
 
-  return rtnval;
+     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.
+
+   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.
@@ -2235,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.  */
@@ -2288,14 +2343,14 @@ emacs_full_write (int fildes, char const *buf, ptrdiff_t nbyte,
    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, char const *buf, ptrdiff_t nbyte)
+emacs_write (int fildes, void const *buf, ptrdiff_t nbyte)
 {
   return emacs_full_write (fildes, buf, nbyte, 0);
 }
 
 /* Like emacs_write, but also process pending signals if interrupted.  */
 ptrdiff_t
-emacs_write_sig (int fildes, char const *buf, ptrdiff_t nbyte)
+emacs_write_sig (int fildes, void const *buf, ptrdiff_t nbyte)
 {
   return emacs_full_write (fildes, buf, nbyte, 1);
 }
@@ -2333,7 +2388,7 @@ emacs_perror (char const *message)
    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;
@@ -2360,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;
@@ -2386,14 +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 = emacs_open (port, O_RDWR | O_NOCTTY | O_NONBLOCK, 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
@@ -2433,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);
@@ -2441,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;
@@ -2458,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.  */
@@ -2581,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);
@@ -2681,7 +2732,7 @@ list_system_processes (void)
 #endif /* !defined (WINDOWSNT) */
 
 #if defined GNU_LINUX && defined HAVE_LONG_LONG_INT
-static EMACS_TIME
+static struct timespec
 time_from_jiffies (unsigned long long tval, long hz)
 {
   unsigned long long s = tval / hz;
@@ -2690,34 +2741,34 @@ 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 = emacs_fopen ("/proc/uptime", "r");
@@ -2735,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);
     }
@@ -2761,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 = emacs_fopen ("/proc/tty/drivers", "r");
+  name[0] = 0;
 
   if (fdev)
     {
@@ -2774,7 +2826,7 @@ 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 (fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor) >= 3
              && major == MAJOR (rdev))
@@ -2800,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 = 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 (fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value) >= 2
-             && strcmp (entry_name, "MemTotal:") == 0)
-           {
-             retval = entry_value;
-             break;
-           }
-       }
       fclose (fmem);
     }
   unblock_input ();
@@ -2846,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;
@@ -2854,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);
@@ -2885,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;
@@ -2913,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;
@@ -2966,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);
@@ -2993,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);
     }
 
@@ -3095,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);
@@ -3123,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
@@ -3212,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;
@@ -3254,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);
   {
@@ -3306,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,
@@ -3316,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)),
@@ -3329,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;