/* 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-2013 Free Software
+ Foundation, Inc.
This file is part of GNU Emacs.
#include <config.h>
-#define SYSTIME_INLINE EXTERN_INLINE
-
-#include <ctype.h>
-#include <signal.h>
-#include <stdio.h>
-#include <setjmp.h>
+#include <execinfo.h>
+#include "sysstdio.h"
#ifdef HAVE_PWD_H
#include <pwd.h>
#include <grp.h>
#include <limits.h>
#include <unistd.h>
-#include <allocator.h>
-#include <careadlinkat.h>
-#include <ignore-value.h>
+#include <c-ctype.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
#define read sys_read
#define write sys_write
+#ifndef STDERR_FILENO
+#define STDERR_FILENO fileno(GetStdHandle(STD_ERROR_HANDLE))
+#endif
#include <windows.h>
#endif /* not WINDOWSNT */
#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>
#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);
-#if defined TIOCNOTTY || defined USG5 || defined CYGWIN
-static _Noreturn void croak (char *);
-#endif
+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
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
return NULL;
strcpy (buf, pwd);
}
-#ifdef HAVE_GETCWD
else
{
size_t buf_size = 1024;
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
\f
-/* Set nonzero to make following function work under dbx
- (at least for bsd). */
-int wait_debugging EXTERNALLY_VISIBLE;
-
#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)
- {
-#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 waitpid and make the process go away. */
- /* There is some indication that there is a bug involved with
- termination of subprocesses, perhaps involving a kernel bug too,
- but no idea what it is. Just as a hunch we signal SIGCHLD to see
- if that causes the problem to go away or get worse. */
- sigsetmask (sigmask (SIGCHLD));
- if (0 > kill (pid, 0))
- {
- sigsetmask (SIGEMPTYMASK);
- kill (getpid (), SIGCHLD);
- break;
- }
- if (wait_debugging)
- sleep (1);
- else
- sigpause (SIGEMPTYMASK);
-#else /* not BSD_SYSTEM, and not HPUX version >= 6 */
-#ifdef WINDOWSNT
- wait (0);
- break;
-#else /* not WINDOWSNT */
- sigblock (sigmask (SIGCHLD));
- errno = 0;
- if (kill (pid, 0) == -1 && errno == ESRCH)
- {
- sigunblock (sigmask (SIGCHLD));
- break;
- }
+ pid_t pid;
- sigsuspend (&empty_mask);
-#endif /* not WINDOWSNT */
-#endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
+ /* 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.
#endif /* not MSDOS */
\f
-/* Record a signal code and the handler for it. */
+/* Record a signal code and the action for it. */
struct save_signal
{
int code;
- void (*handler) (int);
+ struct sigaction action;
};
static void save_signal_handlers (struct save_signal *);
void
sys_suspend (void)
{
-#if defined (SIGTSTP) && !defined (MSDOS)
-
- {
- int pgrp = EMACS_GETPGRP (0);
- 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. */
{
#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
- int pid;
+ 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;
saved_handlers[2].code = SIGTERM;
-#ifdef SIGIO
+#ifdef USABLE_SIGIO
saved_handlers[3].code = SIGIO;
saved_handlers[4].code = 0;
#else
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)
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");
if (epwd)
{
strcpy (old_pwd, epwd);
- if (str[len - 1] == '/')
- str[len - 1] = '\0';
setenv ("PWD", str, 1);
}
st = system (sh);
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 */
}
/* 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
{
while (saved_handlers->code)
{
- saved_handlers->handler
- = (void (*) (int)) signal (saved_handlers->code, SIG_IGN);
+ struct sigaction action;
+ emacs_sigaction_init (&action, SIG_IGN);
+ sigaction (saved_handlers->code, &action, &saved_handlers->action);
saved_handlers++;
}
}
{
while (saved_handlers->code)
{
- signal (saved_handlers->code, saved_handlers->handler);
+ sigaction (saved_handlers->code, &saved_handlers->action, 0);
saved_handlers++;
}
}
\f
-#ifndef SIGIO
-/* If SIGIO is broken, don't do anything. */
-void
-init_sigio (int fd)
-{
-}
-
-static void
-reset_sigio (int fd)
-{
-}
-
-void
-request_sigio (void)
-{
-}
-
-void
-unrequest_sigio (void)
-{
-}
-
-#else
-#ifdef F_SETFL
-
-static int old_fcntl_flags[MAXDESC];
+#ifdef USABLE_SIGIO
+static int old_fcntl_flags[FD_SETSIZE];
+#endif
void
init_sigio (int fd)
{
-#ifdef FASYNC
+#ifdef USABLE_SIGIO
old_fcntl_flags[fd] = fcntl (fd, F_GETFL, 0) & ~FASYNC;
fcntl (fd, F_SETFL, old_fcntl_flags[fd] | FASYNC);
-#endif
interrupts_deferred = 0;
+#endif
}
static void
reset_sigio (int fd)
{
-#ifdef FASYNC
+#ifdef USABLE_SIGIO
fcntl (fd, F_SETFL, old_fcntl_flags[fd]);
#endif
}
-#ifdef FASYNC /* F_SETFL does not imply existence of FASYNC */
-/* XXX Uhm, FASYNC is not used anymore here. */
-/* XXX Yeah, but you need it for SIGIO, don't you? */
-
void
request_sigio (void)
{
+#ifdef USABLE_SIGIO
+ sigset_t unblocked;
+
if (noninteractive)
return;
-#ifdef SIGWINCH
- sigunblock (sigmask (SIGWINCH));
-#endif
- sigunblock (sigmask (SIGIO));
+ sigemptyset (&unblocked);
+# ifdef SIGWINCH
+ sigaddset (&unblocked, SIGWINCH);
+# endif
+ sigaddset (&unblocked, SIGIO);
+ pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
interrupts_deferred = 0;
+#endif
}
void
unrequest_sigio (void)
{
+#ifdef USABLE_SIGIO
+ sigset_t blocked;
+
if (noninteractive)
return;
-#if 0 /* XXX What's wrong with blocking SIGIO under X? */
- if (x_display_list)
- return;
+ sigemptyset (&blocked);
+# ifdef SIGWINCH
+ sigaddset (&blocked, SIGWINCH);
+# endif
+ sigaddset (&blocked, SIGIO);
+ pthread_sigmask (SIG_BLOCK, &blocked, 0);
+ interrupts_deferred = 1;
#endif
+}
-#ifdef SIGWINCH
- sigblock (sigmask (SIGWINCH));
+void
+ignore_sigio (void)
+{
+#ifdef USABLE_SIGIO
+ signal (SIGIO, SIG_IGN);
#endif
- sigblock (sigmask (SIGIO));
- interrupts_deferred = 1;
}
-#else /* no FASYNC */
-#ifndef MSDOS
+\f
+/* Saving and restoring the process group of Emacs's terminal. */
+
+/* The process group of which Emacs was a member when it initially
+ started.
+
+ If Emacs was in its own process group (i.e. inherited_pgroup ==
+ getpid ()), then we know we're running under a shell with job
+ control (Emacs would never be run as part of a pipeline).
+ Everything is fine.
+
+ If Emacs was not in its own process group, then we know we're
+ running under a shell (or a caller) that doesn't know how to
+ separate itself from Emacs (like sh). Emacs must be in its own
+ process group in order to receive SIGIO correctly. In this
+ situation, we put ourselves in our own pgroup, forcibly set the
+ tty's pgroup to our pgroup, and make sure to restore and reinstate
+ the tty's pgroup just like any other terminal setting. If
+ inherited_group was not the tty's pgroup, then we'll get a
+ SIGTTmumble when we try to change the tty's pgroup, and a CONT if
+ it goes foreground in the future, which is what should happen. */
+
+static pid_t inherited_pgroup;
void
-request_sigio (void)
+init_foreground_group (void)
{
- if (noninteractive || read_socket_hook)
- return;
+ pid_t pgrp = getpgrp ();
+ inherited_pgroup = getpid () == pgrp ? 0 : pgrp;
+}
+
+/* Block and unblock SIGTTOU. */
- croak ("request_sigio");
+void
+block_tty_out_signal (void)
+{
+#ifdef SIGTTOU
+ sigset_t blocked;
+ sigemptyset (&blocked);
+ sigaddset (&blocked, SIGTTOU);
+ pthread_sigmask (SIG_BLOCK, &blocked, 0);
+#endif
}
void
-unrequest_sigio (void)
+unblock_tty_out_signal (void)
{
- if (noninteractive || read_socket_hook)
- return;
+#ifdef SIGTTOU
+ pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+#endif
+}
- croak ("unrequest_sigio");
+/* 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
+ annoyance, so temporarily ignore the signal.
+
+ In practice, platforms lacking SIGTTOU also lack tcsetpgrp, so
+ skip all this unless SIGTTOU is defined. */
+static void
+tcsetpgrp_without_stopping (int fd, pid_t pgid)
+{
+#ifdef SIGTTOU
+ block_input ();
+ block_tty_out_signal ();
+ tcsetpgrp (fd, pgid);
+ unblock_tty_out_signal ();
+ unblock_input ();
+#endif
}
-#endif /* MSDOS */
-#endif /* FASYNC */
-#endif /* F_SETFL */
-#endif /* SIGIO */
+/* Split off the foreground process group to Emacs alone. When we are
+ in the foreground, but not started in our own process group,
+ redirect the tty device handle FD to point to our own process
+ group. FD must be the file descriptor of the controlling tty. */
+static void
+narrow_foreground_group (int fd)
+{
+ if (inherited_pgroup && setpgid (0, 0) == 0)
+ tcsetpgrp_without_stopping (fd, getpid ());
+}
+/* Set the tty to our original foreground group. */
+static void
+widen_foreground_group (int fd)
+{
+ if (inherited_pgroup && setpgid (0, inherited_pgroup) == 0)
+ tcsetpgrp_without_stopping (fd, inherited_pgroup);
+}
\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
\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,
if (!tty_out->output)
return; /* The tty is suspended. */
+ narrow_foreground_group (fileno (tty_out->input));
+
if (! tty_out->old_tty)
tty_out->old_tty = xmalloc (sizeof *tty_out->old_tty);
#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)] =
#endif /* HAVE_GPM */
}
#endif /* F_GETOWN */
-#endif /* F_SETFL */
#ifdef _IOFBF
/* This symbol is defined on recent USG systems.
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;
}
/* 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)
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
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 */
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));
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),
dos_ttcooked ();
#endif
+ widen_foreground_group (fileno (tty_out->input));
}
\f
#ifdef HAVE_PTYS
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
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.
}
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);
}
#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 = '-';
}
}
\f
-/* POSIX signals support - DJB */
-/* Anyone with POSIX signals should have ANSI C declarations */
-
sigset_t empty_mask;
-#ifndef WINDOWSNT
+static struct sigaction process_fatal_action;
-signal_handler_t
-sys_signal (int signal_number, signal_handler_t action)
-{
- struct sigaction new_action, old_action;
- sigemptyset (&new_action.sa_mask);
- new_action.sa_handler = action;
- new_action.sa_flags = 0;
-#if defined (SA_RESTART)
- /* Emacs mostly works better with restartable system services. If this
- flag exists, we probably want to turn it on here.
- However, on some systems (only hpux11 at present) this resets the
- timeout of `select' which means that `select' never finishes if
- it keeps getting signals.
- We define BROKEN_SA_RESTART on those systems. */
- /* It's not clear why the comment above says "mostly works better". --Stef
- When SYNC_INPUT is set, we don't want SA_RESTART because we need to poll
+static int
+emacs_sigaction_flags (void)
+{
+#ifdef SA_RESTART
+ /* SA_RESTART causes interruptible functions with timeouts (e.g.,
+ 'select') to reset their timeout on some platforms (e.g.,
+ HP-UX 11), which is not what we want. Also, when Emacs is
+ interactive, we don't want SA_RESTART because we need to poll
for pending input so we need long-running syscalls to be interrupted
- after a signal that sets the interrupt_input_pending flag. */
- /* Non-interactive keyboard input goes through stdio, where we always
- want restartable system calls. */
-# if defined (BROKEN_SA_RESTART) || defined (SYNC_INPUT)
+ after a signal that sets pending_signals.
+
+ Non-interactive keyboard input goes through stdio, where we
+ always want restartable system calls. */
if (noninteractive)
-# endif
- new_action.sa_flags = SA_RESTART;
+ return SA_RESTART;
+#endif
+ return 0;
+}
+
+/* Store into *ACTION a signal action suitable for Emacs, with handler
+ HANDLER. */
+void
+emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
+{
+ sigemptyset (&action->sa_mask);
+
+ /* When handling a signal, block nonfatal system signals that are caught
+ by Emacs. This makes race conditions less likely. */
+ sigaddset (&action->sa_mask, SIGALRM);
+ sigaddset (&action->sa_mask, SIGCHLD);
+#ifdef SIGDANGER
+ sigaddset (&action->sa_mask, SIGDANGER);
+#endif
+#ifdef PROFILER_CPU_SUPPORT
+ sigaddset (&action->sa_mask, SIGPROF);
+#endif
+#ifdef SIGWINCH
+ sigaddset (&action->sa_mask, SIGWINCH);
+#endif
+ if (! noninteractive)
+ {
+ sigaddset (&action->sa_mask, SIGINT);
+ sigaddset (&action->sa_mask, SIGQUIT);
+#ifdef USABLE_SIGIO
+ sigaddset (&action->sa_mask, SIGIO);
#endif
- sigaction (signal_number, &new_action, &old_action);
- return (old_action.sa_handler);
+ }
+
+ if (! IEEE_FLOATING_POINT)
+ sigaddset (&action->sa_mask, SIGFPE);
+
+ action->sa_handler = handler;
+ action->sa_flags = emacs_sigaction_flags ();
}
-#endif /* WINDOWSNT */
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+static pthread_t main_thread;
+#endif
+
+/* SIG has arrived at the current process. Deliver it to the main
+ thread, which should handle it with HANDLER.
-#ifndef __GNUC__
-/* If we're compiling with GCC, we don't need this function, since it
- can be written as a macro. */
-sigset_t
-sys_sigmask (int sig)
+ If we are on the main thread, handle the signal SIG with HANDLER.
+ Otherwise, redirect the signal to the main thread, blocking it from
+ this thread. POSIX says any thread can receive a signal that is
+ associated with a process, process group, or asynchronous event.
+ On GNU/Linux that is not true, but for other systems (FreeBSD at
+ least) it is. */
+void
+deliver_process_signal (int sig, signal_handler_t handler)
{
- sigset_t mask;
- sigemptyset (&mask);
- sigaddset (&mask, sig);
- return mask;
+ /* Preserve errno, to avoid race conditions with signal handlers that
+ might change errno. Races can occur even in single-threaded hosts. */
+ int old_errno = errno;
+
+ bool on_main_thread = true;
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+ if (! pthread_equal (pthread_self (), main_thread))
+ {
+ sigset_t blocked;
+ sigemptyset (&blocked);
+ sigaddset (&blocked, sig);
+ pthread_sigmask (SIG_BLOCK, &blocked, 0);
+ pthread_kill (main_thread, sig);
+ on_main_thread = false;
+ }
+#endif
+ if (on_main_thread)
+ handler (sig);
+
+ errno = old_errno;
}
+
+/* Static location to save a fatal backtrace in a thread.
+ FIXME: If two subsidiary threads fail simultaneously, the resulting
+ backtrace may be garbage. */
+enum { BACKTRACE_LIMIT_MAX = 500 };
+static void *thread_backtrace_buffer[BACKTRACE_LIMIT_MAX + 1];
+static int thread_backtrace_npointers;
+
+/* SIG has arrived at the current thread.
+ If we are on the main thread, handle the signal SIG with HANDLER.
+ Otherwise, this is a fatal error in the handling thread. */
+static void
+deliver_thread_signal (int sig, signal_handler_t handler)
+{
+ int old_errno = errno;
+
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+ if (! pthread_equal (pthread_self (), main_thread))
+ {
+ thread_backtrace_npointers
+ = backtrace (thread_backtrace_buffer, BACKTRACE_LIMIT_MAX);
+ sigaction (sig, &process_fatal_action, 0);
+ pthread_kill (main_thread, sig);
+
+ /* Avoid further damage while the main thread is exiting. */
+ while (1)
+ sigsuspend (&empty_mask);
+ }
+#endif
+
+ handler (sig);
+ errno = old_errno;
+}
+\f
+#if !HAVE_DECL_SYS_SIGLIST
+# 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];
+# endif
#endif
-/* I'd like to have these guys return pointers to the mask storage in here,
- but there'd be trouble if the code was saving multiple masks. I'll be
- safe and pass the structure. It normally won't be more than 2 bytes
- anyhow. - DJB */
+#ifdef _sys_nsig
+# define sys_siglist_entries _sys_nsig
+#else
+# define sys_siglist_entries NSIG
+#endif
-sigset_t
-sys_sigblock (sigset_t new_mask)
+/* Handle bus errors, invalid instruction, etc. */
+static void
+handle_fatal_signal (int sig)
{
- sigset_t old_mask;
- pthread_sigmask (SIG_BLOCK, &new_mask, &old_mask);
- return (old_mask);
+ terminate_due_to_signal (sig, 40);
}
-sigset_t
-sys_sigunblock (sigset_t new_mask)
+static void
+deliver_fatal_signal (int sig)
{
- sigset_t old_mask;
- pthread_sigmask (SIG_UNBLOCK, &new_mask, &old_mask);
- return (old_mask);
+ deliver_process_signal (sig, handle_fatal_signal);
}
-sigset_t
-sys_sigsetmask (sigset_t new_mask)
+static void
+deliver_fatal_thread_signal (int sig)
{
- sigset_t old_mask;
- pthread_sigmask (SIG_SETMASK, &new_mask, &old_mask);
- return (old_mask);
+ deliver_thread_signal (sig, handle_fatal_signal);
}
-\f
-#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
-static char *my_sys_siglist[NSIG];
-# ifdef sys_siglist
-# undef sys_siglist
-# endif
-# define sys_siglist my_sys_siglist
+static _Noreturn void
+handle_arith_signal (int sig)
+{
+ pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+ xsignal0 (Qarith_error);
+}
+
+static void
+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
+maybe_fatal_sig (int sig)
+{
+ bool catch_sig = !noninteractive;
+ if (!catch_sig)
+ {
+ struct sigaction old_action;
+ sigaction (sig, 0, &old_action);
+ catch_sig = old_action.sa_handler != SIG_IGN;
+ }
+ if (catch_sig)
+ sigaction (sig, &process_fatal_action, 0);
+}
+
void
-init_signals (void)
+init_signals (bool dumping)
{
+ struct sigaction thread_fatal_action;
+ struct sigaction action;
+
sigemptyset (&empty_mask);
-#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+ main_thread = pthread_self ();
+#endif
+
+#if !HAVE_DECL_SYS_SIGLIST && !defined _sys_siglist
if (! initialized)
{
-# ifdef SIGABRT
sys_siglist[SIGABRT] = "Aborted";
-# endif
# 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
# ifdef SIGCONT
sys_siglist[SIGCONT] = "Continued";
# endif
# ifdef SIGEMT
sys_siglist[SIGEMT] = "Emulation trap";
# endif
-# ifdef SIGFPE
sys_siglist[SIGFPE] = "Arithmetic exception";
-# endif
# ifdef SIGFREEZE
sys_siglist[SIGFREEZE] = "SIGFREEZE";
# endif
# ifdef SIGGRANT
sys_siglist[SIGGRANT] = "Monitor mode granted";
# endif
-# ifdef SIGHUP
sys_siglist[SIGHUP] = "Hangup";
-# endif
-# ifdef SIGILL
sys_siglist[SIGILL] = "Illegal instruction";
-# endif
-# ifdef SIGINT
sys_siglist[SIGINT] = "Interrupt";
-# endif
# ifdef SIGIO
sys_siglist[SIGIO] = "I/O possible";
# endif
# ifdef SIGIOT
sys_siglist[SIGIOT] = "IOT trap";
# endif
-# ifdef SIGKILL
sys_siglist[SIGKILL] = "Killed";
-# endif
# ifdef SIGLOST
sys_siglist[SIGLOST] = "Resource lost";
# endif
# ifdef SIGPHONE
sys_siglist[SIGWIND] = "SIGPHONE";
# endif
-# ifdef SIGPIPE
sys_siglist[SIGPIPE] = "Broken pipe";
-# endif
# ifdef SIGPOLL
sys_siglist[SIGPOLL] = "Pollable event occurred";
# endif
# 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
# ifdef SIGSAK
sys_siglist[SIGSAK] = "Secure attention";
# endif
-# ifdef SIGSEGV
sys_siglist[SIGSEGV] = "Segmentation violation";
-# endif
# ifdef SIGSOUND
sys_siglist[SIGSOUND] = "Sound completed";
# endif
# ifdef SIGSYS
sys_siglist[SIGSYS] = "Bad argument to system call";
# endif
-# ifdef SIGTERM
sys_siglist[SIGTERM] = "Terminated";
-# endif
# ifdef SIGTHAW
sys_siglist[SIGTHAW] = "SIGTHAW";
# endif
sys_siglist[SIGXFSZ] = "File size limit exceeded";
# endif
}
-#endif /* !defined HAVE_STRSIGNAL && !defined HAVE_DECL_SYS_SIGLIST */
+#endif /* !HAVE_DECL_SYS_SIGLIST && !_sys_siglist */
+
+ /* Don't alter signal handlers if dumping. On some machines,
+ changing signal handlers sets static data that would make signals
+ fail to work right when the dumped Emacs is run. */
+ if (dumping)
+ return;
+
+ sigfillset (&process_fatal_action.sa_mask);
+ process_fatal_action.sa_handler = deliver_fatal_signal;
+ process_fatal_action.sa_flags = emacs_sigaction_flags ();
+
+ sigfillset (&thread_fatal_action.sa_mask);
+ thread_fatal_action.sa_handler = deliver_fatal_thread_signal;
+ thread_fatal_action.sa_flags = process_fatal_action.sa_flags;
+
+ /* SIGINT may need special treatment on MS-Windows. See
+ http://lists.gnu.org/archive/html/emacs-devel/2010-09/msg01062.html
+ Please update the doc of kill-emacs, kill-emacs-hook, and
+ NEWS if you change this. */
+
+ maybe_fatal_sig (SIGHUP);
+ maybe_fatal_sig (SIGINT);
+ maybe_fatal_sig (SIGTERM);
+
+ /* Emacs checks for write errors, so it can safely ignore SIGPIPE.
+ However, in batch mode leave SIGPIPE alone, as that causes Emacs
+ to behave more like typical batch applications do. */
+ if (! noninteractive)
+ signal (SIGPIPE, SIG_IGN);
+
+ sigaction (SIGQUIT, &process_fatal_action, 0);
+ sigaction (SIGILL, &thread_fatal_action, 0);
+ sigaction (SIGTRAP, &thread_fatal_action, 0);
+
+ /* Typically SIGFPE is thread-specific and is fatal, like SIGILL.
+ But on a non-IEEE host SIGFPE can come from a trap in the Lisp
+ interpreter's floating point operations, so treat SIGFPE as an
+ arith-error if it arises in the main thread. */
+ if (IEEE_FLOATING_POINT)
+ sigaction (SIGFPE, &thread_fatal_action, 0);
+ else
+ {
+ emacs_sigaction_init (&action, deliver_arith_signal);
+ sigaction (SIGFPE, &action, 0);
+ }
+
+#ifdef SIGUSR1
+ add_user_signal (SIGUSR1, "sigusr1");
+#endif
+#ifdef SIGUSR2
+ add_user_signal (SIGUSR2, "sigusr2");
+#endif
+ sigaction (SIGABRT, &thread_fatal_action, 0);
+#ifdef SIGPRE
+ sigaction (SIGPRE, &thread_fatal_action, 0);
+#endif
+#ifdef SIGORE
+ sigaction (SIGORE, &thread_fatal_action, 0);
+#endif
+#ifdef SIGUME
+ sigaction (SIGUME, &thread_fatal_action, 0);
+#endif
+#ifdef SIGDLK
+ sigaction (SIGDLK, &process_fatal_action, 0);
+#endif
+#ifdef SIGCPULIM
+ sigaction (SIGCPULIM, &process_fatal_action, 0);
+#endif
+#ifdef SIGIOT
+ sigaction (SIGIOT, &thread_fatal_action, 0);
+#endif
+#ifdef SIGEMT
+ sigaction (SIGEMT, &thread_fatal_action, 0);
+#endif
+#ifdef SIGBUS
+ sigaction (SIGBUS, &thread_fatal_action, 0);
+#endif
+ sigaction (SIGSEGV, &thread_fatal_action, 0);
+#ifdef SIGSYS
+ sigaction (SIGSYS, &thread_fatal_action, 0);
+#endif
+ sigaction (SIGTERM, &process_fatal_action, 0);
+#ifdef SIGPROF
+ signal (SIGPROF, SIG_IGN);
+#endif
+#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
+
+#ifdef SIGDANGER
+ /* This just means available memory is getting low. */
+ emacs_sigaction_init (&action, deliver_danger_signal);
+ sigaction (SIGDANGER, &action, 0);
+#endif
+
+ /* AIX-specific signals. */
+#ifdef SIGGRANT
+ sigaction (SIGGRANT, &process_fatal_action, 0);
+#endif
+#ifdef SIGMIGRATE
+ sigaction (SIGMIGRATE, &process_fatal_action, 0);
+#endif
+#ifdef SIGMSG
+ sigaction (SIGMSG, &process_fatal_action, 0);
+#endif
+#ifdef SIGRETRACT
+ sigaction (SIGRETRACT, &process_fatal_action, 0);
+#endif
+#ifdef SIGSAK
+ sigaction (SIGSAK, &process_fatal_action, 0);
+#endif
+#ifdef SIGSOUND
+ sigaction (SIGSOUND, &process_fatal_action, 0);
+#endif
+#ifdef SIGTALRM
+ sigaction (SIGTALRM, &thread_fatal_action, 0);
+#endif
}
\f
#ifndef HAVE_RANDOM
#endif /* !RAND_BITS */
void
-seed_random (long int arg)
+seed_random (void *seed, ptrdiff_t seed_size)
{
+#if defined HAVE_RANDOM || ! defined HAVE_LRAND48
+ unsigned int arg = 0;
+#else
+ long int arg = 0;
+#endif
+ unsigned char *argp = (unsigned char *) &arg;
+ unsigned char *seedp = seed;
+ ptrdiff_t i;
+ for (i = 0; i < seed_size; i++)
+ argp[i % sizeof arg] ^= seedp[i];
#ifdef HAVE_RANDOM
- srandom ((unsigned int)arg);
+ srandom (arg);
#else
# ifdef HAVE_LRAND48
srand48 (arg);
# else
- srand ((unsigned int)arg);
+ srand (arg);
# endif
#endif
}
+void
+init_random (void)
+{
+ struct timespec t = current_timespec ();
+ uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec;
+ seed_random (&v, sizeof v);
+}
+
/*
* Return a nonnegative random integer out of whatever we've got.
* It contains enough bits to make a random (signed) Emacs fixnum.
}
#endif
\f
-int
-emacs_open (const char *path, int oflag, int mode)
+/* If a backtrace is available, output the top lines of it to stderr.
+ Do not output more than BACKTRACE_LIMIT or BACKTRACE_LIMIT_MAX lines.
+ This function may be called from a signal handler, so it should
+ not invoke async-unsafe functions like malloc. */
+void
+emacs_backtrace (int backtrace_limit)
{
- register int rtnval;
+ void *main_backtrace_buffer[BACKTRACE_LIMIT_MAX + 1];
+ int bounded_limit = min (backtrace_limit, BACKTRACE_LIMIT_MAX);
+ void *buffer;
+ int npointers;
- while ((rtnval = open (path, oflag, mode)) == -1
- && (errno == EINTR))
+ if (thread_backtrace_npointers)
+ {
+ buffer = thread_backtrace_buffer;
+ npointers = thread_backtrace_npointers;
+ }
+ else
+ {
+ buffer = main_backtrace_buffer;
+ npointers = backtrace (buffer, bounded_limit + 1);
+ }
+
+ if (npointers)
+ {
+ emacs_write (STDERR_FILENO, "\nBacktrace:\n", 12);
+ backtrace_symbols_fd (buffer, npointers, STDERR_FILENO);
+ if (bounded_limit < npointers)
+ emacs_write (STDERR_FILENO, "...\n", 4);
+ }
+}
+\f
+#ifndef HAVE_NTGUI
+void
+emacs_abort (void)
+{
+ 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 *file, int oflags, int mode)
+{
+ 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;
+ 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;
+}
- 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.
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. */
}
/* 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)
{
-#ifdef SYNC_INPUT
/* I originally used `QUIT' but that might causes files to
be truncated if you hit C-g in the middle of it. --Stef */
- process_pending_signals ();
-#endif
+ if (process_signals && pending_signals)
+ process_pending_signals ();
continue;
}
else
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);
-
- BLOCK_INPUT; /* getcwd uses malloc */
- spath = npath = getcwd ((char *) 0, MAXPATHLEN);
- if (spath == 0)
- {
- UNBLOCK_INPUT;
- return spath;
- }
- /* 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;
+ return emacs_full_write (fildes, buf, nbyte, 1);
}
-#endif /* !defined (HAVE_GETWD) || defined (BROKEN_GETWD) */
-
-/*
- * This function will go away as soon as all the stubs fixed. (fnf)
- */
-
+/* 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
-croak (char *badfunc)
-{
- printf ("%s not yet implemented\r\n", badfunc);
- reset_all_sys_modes ();
- exit (1);
-}
-
-#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;
+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
+ {
+ 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);
+ }
+ 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;
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;
return fdutimens (fd, filename, timespec);
}
\f
-#ifndef HAVE_STRSIGNAL
-char *
-strsignal (int code)
+/* Like strsignal, except async-signal-safe, and this function typically
+ returns a string in the C locale rather than the current locale. */
+char const *
+safe_strsignal (int code)
{
- char *signame = 0;
+ char const *signame = 0;
- if (0 <= code && code < NSIG)
- {
- /* Cast to suppress warning if the table has const char *. */
- signame = (char *) sys_siglist[code];
- }
+ if (0 <= code && code < sys_siglist_entries)
+ signame = sys_siglist[code];
+ if (! signame)
+ signame = "Unknown signal";
return signame;
}
-#endif /* HAVE_STRSIGNAL */
\f
#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
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);
/* 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;
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. */
/* 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 (p, childp, childp2);
-
+ pset_childp (p, childp2);
}
#endif /* not DOS_NT */
\f
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};
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
#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;
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");
+ block_input ();
+ fup = emacs_fopen ("/proc/uptime", "r");
if (fup)
{
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);
}
- UNBLOCK_INPUT;
+ unblock_input ();
return up;
}
static Lisp_Object
procfs_ttyname (int rdev)
{
- FILE *fdev = NULL;
+ FILE *fdev;
char name[PATH_MAX];
- BLOCK_INPUT;
- fdev = fopen ("/proc/tty/drivers", "r");
+ block_input ();
+ fdev = emacs_fopen ("/proc/tty/drivers", "r");
+ name[0] = 0;
if (fdev)
{
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);
}
fclose (fdev);
}
- UNBLOCK_INPUT;
+ unblock_input ();
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");
+ 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 (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value)
- && strcmp (entry_name, "MemTotal:") == 0)
- {
- retval = entry_value;
- break;
- }
- }
fclose (fmem);
}
- UNBLOCK_INPUT;
+ unblock_input ();
return retval;
}
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;
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);
/* euid egid */
uid = st.st_uid;
attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs);
- BLOCK_INPUT;
+ block_input ();
pw = getpwuid (uid);
- UNBLOCK_INPUT;
+ unblock_input ();
if (pw)
attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
gid = st.st_gid;
attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid)), attrs);
- BLOCK_INPUT;
+ block_input ();
gr = getgrgid (gid);
- UNBLOCK_INPUT;
+ unblock_input ();
if (gr)
attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
+ count = SPECPDL_INDEX ();
strcpy (fn, procfn);
procfn_end = fn + strlen (fn);
strcpy (procfn_end, "/stat");
fd = emacs_open (fn, O_RDONLY, 0);
- if (fd >= 0 && (nread = emacs_read (fd, procbuf, sizeof (procbuf) - 1)) > 0)
+ if (fd < 0)
+ nread = 0;
+ else
+ {
+ record_unwind_protect_int (close_file_unwind, fd);
+ nread = emacs_read (fd, procbuf, sizeof procbuf - 1);
+ }
+ if (0 < nread)
{
procbuf[nread] = '\0';
p = procbuf;
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;
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);
attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs);
}
}
- if (fd >= 0)
- emacs_close (fd);
+ unbind_to (count, Qnil);
/* args */
strcpy (procfn_end, "/cmdline");
fd = emacs_open (fn, O_RDONLY, 0);
if (fd >= 0)
{
- char ch;
- for (cmdline_size = 0; cmdline_size < STRING_BYTES_BOUND; cmdline_size++)
+ ptrdiff_t readsize, nread_incr;
+ record_unwind_protect_int (close_file_unwind, fd);
+ record_unwind_protect_nothing ();
+ nread = cmdline_size = 0;
+
+ do
{
- if (emacs_read (fd, &ch, 1) != 1)
- break;
- c = ch;
- if (isspace (c) || c == '\\')
- cmdline_size++; /* for later quoting, see below */
+ cmdline = xpalloc (cmdline, &cmdline_size, 2, STRING_BYTES_BOUND, 1);
+ set_unwind_protect_ptr (count + 1, xfree, cmdline);
+
+ /* Leave room even if every byte needs escaping below. */
+ readsize = (cmdline_size >> 1) - nread;
+
+ nread_incr = emacs_read (fd, cmdline + nread, readsize);
+ nread += max (0, nread_incr);
}
- if (cmdline_size)
+ while (nread_incr == readsize);
+
+ if (nread)
{
- cmdline = xmalloc (cmdline_size + 1);
- lseek (fd, 0L, SEEK_SET);
- cmdline[0] = '\0';
- if ((nread = read (fd, cmdline, cmdline_size)) >= 0)
- cmdline[nread++] = '\0';
- else
- {
- /* Assigning zero to `nread' makes us skip the following
- two loops, assign zero to cmdline_size, and enter the
- following `if' clause that handles unknown command
- lines. */
- nread = 0;
- }
/* We don't want trailing null characters. */
- for (p = cmdline + nread; p > cmdline + 1 && !p[-1]; p--)
- nread--;
- for (p = cmdline; p < cmdline + nread; p++)
+ for (p = cmdline + nread; cmdline < p && !p[-1]; p--)
+ continue;
+
+ /* Escape-quote whitespace and backslashes. */
+ q = cmdline + cmdline_size;
+ while (cmdline < p)
{
- /* Escape-quote whitespace and backslashes. */
- if (isspace (*p) || *p == '\\')
- {
- memmove (p + 1, p, nread - (p - cmdline));
- nread++;
- *p++ = '\\';
- }
- else if (*p == '\0')
- *p = ' ';
+ char c = *--p;
+ *--q = c ? c : ' ';
+ if (c_isspace (c) || c == '\\')
+ *--q = '\\';
}
- cmdline_size = nread;
+
+ nread = cmdline + cmdline_size - q;
}
- if (!cmdline_size)
+
+ if (!nread)
{
- cmdline_size = cmdsize + 2;
- cmdline = xmalloc (cmdline_size + 1);
+ nread = cmdsize + 2;
+ cmdline_size = nread + 1;
+ q = cmdline = xrealloc (cmdline, cmdline_size);
+ set_unwind_protect_ptr (count + 1, xfree, cmdline);
sprintf (cmdline, "[%.*s]", cmdsize, cmd);
}
- emacs_close (fd);
/* Command line is encoded in locale-coding-system; decode it. */
- cmd_str = make_unibyte_string (cmdline, cmdline_size);
+ cmd_str = make_unibyte_string (q, nread);
decoded_cmd = code_convert_string_norecord (cmd_str,
Vlocale_coding_system, 0);
- xfree (cmdline);
+ unbind_to (count, Qnil);
attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
}
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);
/* euid egid */
uid = st.st_uid;
attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs);
- BLOCK_INPUT;
+ block_input ();
pw = getpwuid (uid);
- UNBLOCK_INPUT;
+ unblock_input ();
if (pw)
attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
gid = st.st_gid;
attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid)), attrs);
- BLOCK_INPUT;
+ block_input ();
gr = getgrgid (gid);
- UNBLOCK_INPUT;
+ unblock_input ();
if (gr)
attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
+ count = SPECPDL_INDEX ();
strcpy (fn, procfn);
procfn_end = fn + strlen (fn);
strcpy (procfn_end, "/psinfo");
fd = emacs_open (fn, O_RDONLY, 0);
- if (fd >= 0
- && (nread = read (fd, (char*)&pinfo, sizeof (struct psinfo)) > 0))
+ if (fd < 0)
+ nread = 0;
+ else
{
- attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (pinfo.pr_ppid)), attrs);
- attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pinfo.pr_pgid)), attrs);
- attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (pinfo.pr_sid)), attrs);
-
- {
- char state_str[2];
- state_str[0] = pinfo.pr_lwp.pr_sname;
- state_str[1] = '\0';
- tem = build_string (state_str);
- attrs = Fcons (Fcons (Qstate, tem), attrs);
- }
-
- /* FIXME: missing Qttyname. psinfo.pr_ttydev is a dev_t,
- need to get a string from it. */
-
- /* FIXME: missing: Qtpgid */
-
- /* FIXME: missing:
- Qminflt
- Qmajflt
- Qcminflt
- Qcmajflt
-
- Qutime
- Qcutime
- Qstime
- Qcstime
- Are they available? */
-
- attrs = Fcons (Fcons (Qtime, make_lisp_time (pinfo.pr_time)), attrs);
- attrs = Fcons (Fcons (Qctime, make_lisp_time (pinfo.pr_ctime)), attrs);
- attrs = Fcons (Fcons (Qpri, make_number (pinfo.pr_lwp.pr_pri)), attrs);
- attrs = Fcons (Fcons (Qnice, make_number (pinfo.pr_lwp.pr_nice)), attrs);
- attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (pinfo.pr_nlwp)), attrs);
-
- attrs = Fcons (Fcons (Qstart, make_lisp_time (pinfo.pr_start)), attrs);
- attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (pinfo.pr_size)), attrs);
- attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (pinfo.pr_rssize)), attrs);
-
- /* pr_pctcpu and pr_pctmem are unsigned integers in the
- range 0 .. 2**15, representing 0.0 .. 1.0. */
- attrs = Fcons (Fcons (Qpcpu, make_float (100.0 / 0x8000 * pinfo.pr_pctcpu)), attrs);
- attrs = Fcons (Fcons (Qpmem, make_float (100.0 / 0x8000 * pinfo.pr_pctmem)), attrs);
-
- decoded_cmd
- = code_convert_string_norecord (make_unibyte_string (pinfo.pr_fname,
- strlen (pinfo.pr_fname)),
- Vlocale_coding_system, 0);
- attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
- decoded_cmd
- = code_convert_string_norecord (make_unibyte_string (pinfo.pr_psargs,
- strlen (pinfo.pr_psargs)),
- Vlocale_coding_system, 0);
- attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
+ record_unwind_protect (close_file_unwind, fd);
+ nread = emacs_read (fd, &pinfo, sizeof pinfo);
}
- if (fd >= 0)
- emacs_close (fd);
+ if (nread == sizeof pinfo)
+ {
+ attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (pinfo.pr_ppid)), attrs);
+ attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pinfo.pr_pgid)), attrs);
+ attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (pinfo.pr_sid)), attrs);
+ {
+ char state_str[2];
+ state_str[0] = pinfo.pr_lwp.pr_sname;
+ state_str[1] = '\0';
+ attrs = Fcons (Fcons (Qstate, build_string (state_str)), attrs);
+ }
+
+ /* FIXME: missing Qttyname. psinfo.pr_ttydev is a dev_t,
+ need to get a string from it. */
+
+ /* FIXME: missing: Qtpgid */
+
+ /* FIXME: missing:
+ Qminflt
+ Qmajflt
+ Qcminflt
+ Qcmajflt
+
+ Qutime
+ Qcutime
+ Qstime
+ Qcstime
+ Are they available? */
+
+ attrs = Fcons (Fcons (Qtime, make_lisp_time (pinfo.pr_time)), attrs);
+ attrs = Fcons (Fcons (Qctime, make_lisp_time (pinfo.pr_ctime)), attrs);
+ attrs = Fcons (Fcons (Qpri, make_number (pinfo.pr_lwp.pr_pri)), attrs);
+ attrs = Fcons (Fcons (Qnice, make_number (pinfo.pr_lwp.pr_nice)), attrs);
+ attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (pinfo.pr_nlwp)),
+ attrs);
+
+ attrs = Fcons (Fcons (Qstart, make_lisp_time (pinfo.pr_start)), attrs);
+ attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (pinfo.pr_size)),
+ attrs);
+ attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (pinfo.pr_rssize)),
+ attrs);
+
+ /* pr_pctcpu and pr_pctmem are unsigned integers in the
+ range 0 .. 2**15, representing 0.0 .. 1.0. */
+ attrs = Fcons (Fcons (Qpcpu,
+ make_float (100.0 / 0x8000 * pinfo.pr_pctcpu)),
+ attrs);
+ attrs = Fcons (Fcons (Qpmem,
+ make_float (100.0 / 0x8000 * pinfo.pr_pctmem)),
+ attrs);
+
+ decoded_cmd = (code_convert_string_norecord
+ (build_unibyte_string (pinfo.pr_fname),
+ Vlocale_coding_system, 0));
+ attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
+ decoded_cmd = (code_convert_string_norecord
+ (build_unibyte_string (pinfo.pr_psargs),
+ Vlocale_coding_system, 0));
+ attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
+ }
+ unbind_to (count, Qnil);
UNGCPRO;
return attrs;
}
#elif defined __FreeBSD__
-static EMACS_TIME
-timeval_to_EMACS_TIME (struct timeval t)
+static struct timespec
+timeval_to_timespec (struct timeval t)
{
- return make_emacs_time (t.tv_sec, t.tv_usec * 1000);
+ return make_timespec (t.tv_sec, t.tv_usec * 1000);
}
static Lisp_Object
make_lisp_timeval (struct timeval t)
{
- return make_lisp_time (timeval_to_EMACS_TIME (t));
+ return make_lisp_time (timeval_to_timespec (t));
}
Lisp_Object
{
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;
attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (proc.ki_uid)), attrs);
- BLOCK_INPUT;
+ block_input ();
pw = getpwuid (proc.ki_uid);
- UNBLOCK_INPUT;
+ unblock_input ();
if (pw)
attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (proc.ki_svgid)), attrs);
- BLOCK_INPUT;
+ block_input ();
gr = getgrgid (proc.ki_svgid);
- UNBLOCK_INPUT;
+ unblock_input ();
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);
{
attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (proc.ki_pgid)), attrs);
attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (proc.ki_sid)), attrs);
- BLOCK_INPUT;
+ block_input ();
ttyname = proc.ki_tdev == NODEV ? NULL : devname (proc.ki_tdev, S_IFCHR);
- UNBLOCK_INPUT;
+ unblock_input ();
if (ttyname)
attrs = Fcons (Fcons (Qtty, build_string (ttyname)), attrs);
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,
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)),
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;