Merge from trunk.
[bpt/emacs.git] / src / sysdep.c
index a165a9c..4bd1f54 100644 (file)
@@ -26,9 +26,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <pwd.h>
 #include <grp.h>
 #endif /* HAVE_PWD_H */
-#ifdef HAVE_LIMITS_H
 #include <limits.h>
-#endif /* HAVE_LIMITS_H */
 #include <unistd.h>
 
 #include <allocator.h>
@@ -118,6 +116,12 @@ struct utimbuf {
 #endif
 #endif
 
+static int emacs_get_tty (int, struct emacs_tty *);
+static int emacs_set_tty (int, struct emacs_tty *, int);
+#if defined TIOCNOTTY || defined USG5 || defined CYGWIN
+static void croak (char *) NO_RETURN;
+#endif
+
 /* Declare here, including term.h is problematic on some systems.  */
 extern void tputs (const char *, int, int (*)(int));
 
@@ -127,12 +131,6 @@ static const int baud_convert[] =
     1800, 2400, 4800, 9600, 19200, 38400
   };
 
-void croak (char *) NO_RETURN;
-
-/* Temporary used by `sigblock' when defined in terms of signprocmask.  */
-
-SIGMASKTYPE sigprocmask_set;
-
 
 #if !defined (HAVE_GET_CURRENT_DIR_NAME) || defined (BROKEN_GET_CURRENT_DIR_NAME)
 
@@ -291,19 +289,18 @@ init_baud_rate (int fd)
 
 \f
 
-int wait_debugging;   /* Set nonzero to make following function work under dbx
-                        (at least for bsd).  */
+/* Set nonzero to make following function work under dbx
+   (at least for bsd).  */
+int wait_debugging EXTERNALLY_VISIBLE;
 
 #ifndef MSDOS
-/* Wait for subprocess with process id `pid' to terminate and
-   make sure it will get eliminated (not remain forever as a zombie) */
 
-void
-wait_for_termination (int pid)
+static void
+wait_for_termination_1 (int pid, int interruptible)
 {
   while (1)
     {
-#if defined (BSD_SYSTEM) || defined (HPUX)
+#if (defined (BSD_SYSTEM) || defined (HPUX)) && !defined(__GNU__)
       /* Note that kill returns -1 even if the process is just a zombie now.
         But inevitably a SIGCHLD interrupt should be generated
         and child_sig will do wait3 and make the process go away. */
@@ -338,9 +335,27 @@ wait_for_termination (int pid)
       sigsuspend (&empty_mask);
 #endif /* not WINDOWSNT */
 #endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
+      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) */
+
+void
+wait_for_termination (int pid)
+{
+  wait_for_termination_1 (pid, 0);
+}
+
+/* Like the above, but allow keyboard interruption. */
+void
+interruptible_wait_for_termination (int pid)
+{
+  wait_for_termination_1 (pid, 1);
+}
+
 /*
  *     flush any pending output
  *      (may flush input as well; it does not matter the way we use it)
@@ -650,7 +665,7 @@ unrequest_sigio (void)
 #else
 #ifdef F_SETFL
 
-int old_fcntl_flags[MAXDESC];
+static int old_fcntl_flags[MAXDESC];
 
 void
 init_sigio (int fd)
@@ -809,7 +824,7 @@ emacs_set_tty (int fd, struct emacs_tty *settings, int flushp)
 \f
 
 #ifdef F_SETOWN
-int old_fcntl_owner[MAXDESC];
+static int old_fcntl_owner[MAXDESC];
 #endif /* F_SETOWN */
 
 /* This may also be defined in stdio,
@@ -1108,8 +1123,7 @@ tabs_safe_p (int fd)
 void
 get_tty_size (int fd, int *widthp, int *heightp)
 {
-
-#ifdef TIOCGWINSZ
+#if defined TIOCGWINSZ
 
   /* BSD-style.  */
   struct winsize size;
@@ -1122,8 +1136,7 @@ get_tty_size (int fd, int *widthp, int *heightp)
       *heightp = size.ws_row;
     }
 
-#else
-#ifdef TIOCGSIZE
+#elif defined TIOCGSIZE
 
   /* SunOS - style.  */
   struct ttysize size;
@@ -1136,16 +1149,28 @@ get_tty_size (int fd, int *widthp, int *heightp)
       *heightp = size.ts_lines;
     }
 
-#else
-#ifdef MSDOS
+#elif defined WINDOWSNT
+
+  CONSOLE_SCREEN_BUFFER_INFO info;
+  if (GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info))
+    {
+      *widthp = info.srWindow.Right - info.srWindow.Left + 1;
+      *heightp = info.srWindow.Bottom - info.srWindow.Top + 1;
+    }
+  else
+    *widthp = *heightp = 0;
+
+#elif defined MSDOS
+
   *widthp = ScreenCols ();
   *heightp = ScreenRows ();
+
 #else /* system doesn't know size */
+
   *widthp = 0;
   *heightp = 0;
+
 #endif
-#endif /* not SunOS-style */
-#endif /* not BSD-style */
 }
 
 /* Set the logical window size associated with descriptor FD
@@ -1451,7 +1476,7 @@ init_system_name (void)
 /* POSIX signals support - DJB */
 /* Anyone with POSIX signals should have ANSI C declarations */
 
-sigset_t empty_mask, full_mask;
+sigset_t empty_mask;
 
 #ifndef WINDOWSNT
 
@@ -1507,7 +1532,7 @@ sigset_t
 sys_sigblock (sigset_t new_mask)
 {
   sigset_t old_mask;
-  sigprocmask (SIG_BLOCK, &new_mask, &old_mask);
+  pthread_sigmask (SIG_BLOCK, &new_mask, &old_mask);
   return (old_mask);
 }
 
@@ -1515,7 +1540,7 @@ sigset_t
 sys_sigunblock (sigset_t new_mask)
 {
   sigset_t old_mask;
-  sigprocmask (SIG_UNBLOCK, &new_mask, &old_mask);
+  pthread_sigmask (SIG_UNBLOCK, &new_mask, &old_mask);
   return (old_mask);
 }
 
@@ -1523,7 +1548,7 @@ sigset_t
 sys_sigsetmask (sigset_t new_mask)
 {
   sigset_t old_mask;
-  sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
+  pthread_sigmask (SIG_SETMASK, &new_mask, &old_mask);
   return (old_mask);
 }
 
@@ -1540,7 +1565,6 @@ void
 init_signals (void)
 {
   sigemptyset (&empty_mask);
-  sigfillset (&full_mask);
 
 #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
   if (! initialized)
@@ -1757,33 +1781,26 @@ seed_random (long int arg)
 }
 
 /*
- * Build a full Emacs-sized word out of whatever we've got.
+ * Return a nonnegative random integer out of whatever we've got.
+ * It contains enough bits to make a random (signed) Emacs fixnum.
  * This suffices even for a 64-bit architecture with a 15-bit rand.
  */
-long
+EMACS_INT
 get_random (void)
 {
-  long val = random ();
-#if VALBITS > RAND_BITS
-  val = (val << RAND_BITS) ^ random ();
-#if VALBITS > 2*RAND_BITS
-  val = (val << RAND_BITS) ^ random ();
-#if VALBITS > 3*RAND_BITS
-  val = (val << RAND_BITS) ^ random ();
-#if VALBITS > 4*RAND_BITS
-  val = (val << RAND_BITS) ^ random ();
-#endif /* need at least 5 */
-#endif /* need at least 4 */
-#endif /* need at least 3 */
-#endif /* need at least 2 */
-  return val & ((1L << VALBITS) - 1);
+  EMACS_UINT val = 0;
+  int i;
+  for (i = 0; i < (FIXNUM_BITS + RAND_BITS - 1) / RAND_BITS; i++)
+    val = (random () ^ (val << RAND_BITS)
+          ^ (val >> (BITS_PER_EMACS_INT - RAND_BITS)));
+  val ^= val >> (BITS_PER_EMACS_INT - FIXNUM_BITS);
+  return val & INTMASK;
 }
 
 #ifndef HAVE_STRERROR
 #ifndef WINDOWSNT
 char *
-strerror (errnum)
-     int errnum;
+strerror (int errnum)
 {
   extern char *sys_errlist[];
   extern int sys_nerr;
@@ -1825,10 +1842,27 @@ emacs_close (int fd)
   return rtnval;
 }
 
-int
-emacs_read (int fildes, char *buf, unsigned int nbyte)
+/* Maximum number of bytes to read or write in a single system call.
+   This works around a serious bug in Linux kernels before 2.6.16; see
+   <https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=612839>.
+   It's likely to work around similar bugs in other operating systems, so do it
+   on all platforms.  Round INT_MAX down to a page size, with the conservative
+   assumption that page sizes are at most 2**18 bytes (any kernel with a
+   page size larger than that shouldn't have the bug).  */
+#ifndef MAX_RW_COUNT
+#define MAX_RW_COUNT (INT_MAX >> 18 << 18)
+#endif
+
+/* Read from FILEDESC to a buffer BUF with size NBYTE, retrying if interrupted.
+   Return the number of bytes read, which might be less than NBYTE.
+   On error, set errno and return -1.  */
+EMACS_INT
+emacs_read (int fildes, char *buf, EMACS_INT nbyte)
 {
-  register int rtnval;
+  register 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.  */
 
   while ((rtnval = read (fildes, buf, nbyte)) == -1
         && (errno == EINTR))
@@ -1836,18 +1870,22 @@ emacs_read (int fildes, char *buf, unsigned int nbyte)
   return (rtnval);
 }
 
-int
-emacs_write (int fildes, const char *buf, unsigned int 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
+   errno if this is less than NBYTE.  */
+EMACS_INT
+emacs_write (int fildes, const char *buf, EMACS_INT nbyte)
 {
-  register int rtnval, bytes_written;
+  ssize_t rtnval;
+  EMACS_INT bytes_written;
 
   bytes_written = 0;
 
   while (nbyte > 0)
     {
-      rtnval = write (fildes, buf, nbyte);
+      rtnval = write (fildes, buf, min (nbyte, MAX_RW_COUNT));
 
-      if (rtnval == -1)
+      if (rtnval < 0)
        {
          if (errno == EINTR)
            {
@@ -1859,13 +1897,14 @@ emacs_write (int fildes, const char *buf, unsigned int nbyte)
              continue;
            }
          else
-           return (bytes_written ? bytes_written : -1);
+           break;
        }
 
       buf += rtnval;
       nbyte -= rtnval;
       bytes_written += rtnval;
     }
+
   return (bytes_written);
 }
 
@@ -1973,37 +2012,6 @@ perror (void)
 }
 #endif /* HPUX and not HAVE_PERROR */
 
-#ifndef HAVE_DUP2
-
-/*
- *     Emulate BSD dup2.  First close newd if it already exists.
- *     Then, attempt to dup oldd.  If not successful, call dup2 recursively
- *     until we are, then close the unsuccessful ones.
- */
-
-int
-dup2 (int oldd, int newd)
-{
-  register int fd, ret;
-
-  emacs_close (newd);
-
-#ifdef F_DUPFD
-  return fcntl (oldd, F_DUPFD, newd);
-#else
-  fd = dup (old);
-  if (fd == -1)
-    return -1;
-  if (fd == new)
-    return new;
-  ret = dup2 (old,new);
-  emacs_close (fd);
-  return ret;
-#endif
-}
-
-#endif /* not HAVE_DUP2 */
-
 /*
  *     Gettimeofday.  Simulate as much as possible.  Only accurate
  *     to nearest second.  Emacs doesn't use tzp so ignore it for now.
@@ -2205,59 +2213,6 @@ rmdir (char *dpath)
 #endif /* !HAVE_RMDIR */
 
 \f
-#ifndef HAVE_MEMSET
-void *
-memset (void *b, int n, size_t length)
-{
-  unsigned char *p = b;
-  while (length-- > 0)
-    *p++ = n;
-  return b;
-}
-#endif /* !HAVE_MEMSET */
-
-#ifndef HAVE_MEMCPY
-void *
-memcpy (void *b1, void *b2, size_t length)
-{
-  unsigned char *p1 = b1, *p2 = b2;
-  while (length-- > 0)
-    *p1++ = *p2++;
-  return b1;
-}
-#endif /* !HAVE_MEMCPY */
-
-#ifndef HAVE_MEMMOVE
-void *
-memmove (void *b1, void *b2, size_t length)
-{
-  unsigned char *p1 = b1, *p2 = b2;
-  if (p1 < p2 || p1 >= p2 + length)
-    while (length-- > 0)
-      *p1++ = *p2++;
-  else
-    {
-      p1 += length;
-      p2 += length;
-      while (length-- > 0)
-       *--p1 = *--p2;
-    }
-  return b1;
-}
-#endif /* !HAVE_MEMCPY */
-
-#ifndef HAVE_MEMCMP
-int
-memcmp (void *b1, void *b2, size_t length)
-{
-  unsigned char *p1 = b1, *p2 = b2;
-  while (length-- > 0)
-    if (*p1++ != *p2++)
-      return p1[-1] < p2[-1] ? -1 : 1;
-  return 0;
-}
-#endif /* !HAVE_MEMCMP */
-\f
 #ifndef HAVE_STRSIGNAL
 char *
 strsignal (int code)
@@ -2361,7 +2316,8 @@ serial_configure (struct Lisp_Process *p,
   CHECK_NUMBER (tem);
   err = cfsetspeed (&attr, XINT (tem));
   if (err != 0)
-    error ("cfsetspeed(%d) failed: %s", XINT (tem), emacs_strerror (errno));
+    error ("cfsetspeed(%"pI"d) failed: %s", XINT (tem),
+          emacs_strerror (errno));
   childp2 = Fplist_put (childp2, QCspeed, tem);
 
   /* Configure bytesize.  */
@@ -2943,6 +2899,8 @@ system_process_attributes (Lisp_Object pid)
 
 #if PROCFS_FILE_OFFSET_BITS_HACK ==  1
 #define _FILE_OFFSET_BITS 64
+#ifdef _FILE_OFFSET_BITS /* Avoid unused-macro warnings.  */
+#endif
 #endif /* PROCFS_FILE_OFFSET_BITS_HACK ==  1 */
 
 Lisp_Object