along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
-#include <ctype.h>
-#include <signal.h>
+
+#define SYSTIME_INLINE EXTERN_INLINE
+
+#include <execinfo.h>
#include <stdio.h>
-#include <setjmp.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <allocator.h>
+#include <c-ctype.h>
#include <careadlinkat.h>
#include <ignore-value.h>
#include <utimens.h>
#include "sysselect.h"
#include "blockinput.h"
-#ifdef __FreeBSD__
+#ifdef BSD_SYSTEM
+#include <sys/param.h>
#include <sys/sysctl.h>
+#endif
+
+#ifdef __FreeBSD__
#include <sys/user.h>
#include <sys/resource.h>
#include <math.h>
#endif
-#ifdef DARWIN_OS
-#include <sys/sysctl.h>
-#endif
-
#ifdef WINDOWSNT
#define read sys_read
#define write sys_write
#include <sys/stat.h>
#include <errno.h>
-#ifdef HAVE_SETPGID
-#if !defined (USG)
-#undef setpgrp
-#define setpgrp setpgid
-#endif
-#endif
-
/* Get SI_SRPC_DOMAIN, if it is available. */
#ifdef HAVE_SYS_SYSTEMINFO_H
#include <sys/systeminfo.h>
#endif
#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
-#include <dos.h>
-#include "dosfns.h"
#include "msdos.h"
#include <sys/param.h>
#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;
+
+/* ULLONG_MAX is missing on Red Hat Linux 7.3; see Bug#11781. */
+#ifndef ULLONG_MAX
+#define ULLONG_MAX TYPE_MAXIMUM (unsigned long long int)
#endif
/* Declare here, including term.h is problematic on some systems. */
#endif
)
{
- buf = (char *) malloc (strlen (pwd) + 1);
+ buf = malloc (strlen (pwd) + 1);
if (!buf)
return NULL;
strcpy (buf, pwd);
else
{
size_t buf_size = 1024;
- buf = (char *) malloc (buf_size);
+ buf = malloc (buf_size);
if (!buf)
return NULL;
for (;;)
return NULL;
}
buf_size *= 2;
- buf = (char *) realloc (buf, buf_size);
+ buf = realloc (buf, buf_size);
if (!buf)
return NULL;
}
else
{
/* We need MAXPATHLEN here. */
- buf = (char *) malloc (MAXPATHLEN + 1);
+ buf = malloc (MAXPATHLEN + 1);
if (!buf)
return NULL;
if (getwd (buf) == NULL)
\f
-/* Set nonzero to make following function work under dbx
- (at least for bsd). */
-int wait_debugging EXTERNALLY_VISIBLE;
-
#ifndef MSDOS
static void
{
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 wait3 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)
+ int status;
+ int wait_result = waitpid (pid, &status, 0);
+ if (wait_result < 0)
+ {
+ if (errno != EINTR)
+ break;
+ }
+ else
{
- sigunblock (sigmask (SIGCHLD));
+ record_child_status_change (wait_result, status);
break;
}
- sigsuspend (&empty_mask);
#endif /* not WINDOWSNT */
-#endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
if (interruptible)
QUIT;
}
#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 *);
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
goto xyzzy;
dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
- str_volatile = str = (unsigned char *) alloca (SCHARS (dir) + 2);
+ str_volatile = str = alloca (SCHARS (dir) + 2);
len = SCHARS (dir);
memcpy (str, SDATA (dir), len);
if (str[len - 1] != '/') str[len++] = '/';
{
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
-
+#ifdef USABLE_SIGIO
static int old_fcntl_flags[MAXDESC];
+#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;
-#endif
-
-#ifdef SIGWINCH
- sigblock (sigmask (SIGWINCH));
-#endif
- sigblock (sigmask (SIGIO));
+ sigemptyset (&blocked);
+# ifdef SIGWINCH
+ sigaddset (&blocked, SIGWINCH);
+# endif
+ sigaddset (&blocked, SIGIO);
+ pthread_sigmask (SIG_BLOCK, &blocked, 0);
interrupts_deferred = 1;
-}
-
-#else /* no FASYNC */
-#ifndef MSDOS
-
-void
-request_sigio (void)
-{
- if (noninteractive || read_socket_hook)
- return;
-
- croak ("request_sigio");
+#endif
}
void
-unrequest_sigio (void)
+ignore_sigio (void)
{
- if (noninteractive || read_socket_hook)
- return;
-
- croak ("unrequest_sigio");
+#ifdef USABLE_SIGIO
+ signal (SIGIO, SIG_IGN);
+#endif
}
-#endif /* MSDOS */
-#endif /* FASYNC */
-#endif /* F_SETFL */
-#endif /* SIGIO */
-
\f
/* Getting and setting emacs_tty structures. */
return; /* The tty is suspended. */
if (! tty_out->old_tty)
- tty_out->old_tty = (struct emacs_tty *) xmalloc (sizeof (struct emacs_tty));
+ tty_out->old_tty = xmalloc (sizeof *tty_out->old_tty);
emacs_get_tty (fileno (tty_out->input), tty_out->old_tty);
Vsystem_name = build_string (uts.nodename);
#else /* HAVE_GETHOSTNAME */
unsigned int hostname_size = 256;
- char *hostname = (char *) alloca (hostname_size);
+ char *hostname = alloca (hostname_size);
/* Try to get the host name; if the buffer is too short, try
again. Apparently, the only indication gethostname gives of
break;
hostname_size <<= 1;
- hostname = (char *) alloca (hostname_size);
+ hostname = alloca (hostname_size);
}
#ifdef HAVE_SOCKETS
/* Turn the hostname into the official, fully-qualified hostname.
}
}
\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 this resets the timeout of `select'
- which means that `select' never finishes if it keeps getting signals.
- BROKEN_SA_RESTART is defined 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
- sigaction (signal_number, &new_action, &old_action);
- return (old_action.sa_handler);
+ return 0;
}
-#endif /* WINDOWSNT */
-
-#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)
+/* Store into *ACTION a signal action suitable for Emacs, with handler
+ HANDLER. */
+void
+emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
{
- sigset_t mask;
- sigemptyset (&mask);
- sigaddset (&mask, sig);
- return mask;
-}
+ 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);
+#ifdef SIGCHLD
+ sigaddset (&action->sa_mask, SIGCHLD);
+#endif
+#ifdef SIGDANGER
+ sigaddset (&action->sa_mask, SIGDANGER);
+#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
+ }
-/* 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 */
+ if (! IEEE_FLOATING_POINT)
+ sigaddset (&action->sa_mask, SIGFPE);
-sigset_t
-sys_sigblock (sigset_t new_mask)
-{
- sigset_t old_mask;
- pthread_sigmask (SIG_BLOCK, &new_mask, &old_mask);
- return (old_mask);
+ action->sa_handler = handler;
+ action->sa_flags = emacs_sigaction_flags ();
}
-sigset_t
-sys_sigunblock (sigset_t new_mask)
+#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.
+
+ 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 old_mask;
- pthread_sigmask (SIG_UNBLOCK, &new_mask, &old_mask);
- return (old_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;
}
-sigset_t
-sys_sigsetmask (sigset_t new_mask)
+/* 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)
{
- sigset_t old_mask;
- pthread_sigmask (SIG_SETMASK, &new_mask, &old_mask);
- return (old_mask);
-}
+ 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 !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
static char *my_sys_siglist[NSIG];
# define sys_siglist my_sys_siglist
#endif
+/* Handle bus errors, invalid instruction, etc. */
+static void
+handle_fatal_signal (int sig)
+{
+ terminate_due_to_signal (sig, 10);
+}
+
+static void
+deliver_fatal_signal (int sig)
+{
+ deliver_process_signal (sig, handle_fatal_signal);
+}
+
+static void
+deliver_fatal_thread_signal (int sig)
+{
+ deliver_thread_signal (sig, handle_fatal_signal);
+}
+
+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);
+}
+
+/* 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);
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+ main_thread = pthread_self ();
+#endif
+
#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
if (! initialized)
{
-# ifdef SIGABRT
sys_siglist[SIGABRT] = "Aborted";
-# endif
# ifdef SIGAIO
sys_siglist[SIGAIO] = "LAN I/O interrupt";
# 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 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 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
# endif
}
#endif /* !defined HAVE_STRSIGNAL && !defined HAVE_DECL_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
+ sigaction (SIGPROF, &process_fatal_action, 0);
+#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)
+{
+ EMACS_TIME t = current_emacs_time ();
+ uintmax_t v = getpid () ^ EMACS_SECS (t) ^ EMACS_NSECS (t);
+ 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.
return val & INTMASK;
}
-#ifndef HAVE_STRERROR
-#ifndef WINDOWSNT
-char *
-strerror (int errnum)
-{
- extern char *sys_errlist[];
- extern int sys_nerr;
-
- if (errnum >= 0 && errnum < sys_nerr)
- return sys_errlist[errnum];
- return (char *) "Unknown error";
-}
-#endif /* not WINDOWSNT */
-#endif /* ! HAVE_STRERROR */
-
#ifndef HAVE_SNPRINTF
/* Approximate snprintf as best we can on ancient hosts that lack it. */
int
}
#endif
\f
+/* 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)
+{
+ void *main_backtrace_buffer[BACKTRACE_LIMIT_MAX + 1];
+ int bounded_limit = min (backtrace_limit, BACKTRACE_LIMIT_MAX);
+ void *buffer;
+ int npointers;
+
+ 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)
+ {
+ ignore_value (write (STDERR_FILENO, "\nBacktrace:\n", 12));
+ backtrace_symbols_fd (buffer, npointers, STDERR_FILENO);
+ if (bounded_limit < npointers)
+ ignore_value (write (STDERR_FILENO, "...\n", 4));
+ }
+}
+\f
+#ifndef HAVE_NTGUI
+void
+emacs_abort (void)
+{
+ terminate_due_to_signal (SIGABRT, 10);
+}
+#endif
+
int
emacs_open (const char *path, int oflag, int mode)
{
{
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 (pending_signals)
+ process_pending_signals ();
continue;
}
else
* under error conditions.
*/
-#ifndef HAVE_GETWD
+#if !defined (HAVE_GETWD) || defined (BROKEN_GETWD)
#ifndef MAXPATHLEN
/* In 4.1, param.h fails to define this. */
char *npath, *spath;
extern char *getcwd (char *, size_t);
- BLOCK_INPUT; /* getcwd uses malloc */
+ block_input (); /* getcwd uses malloc */
spath = npath = getcwd ((char *) 0, MAXPATHLEN);
if (spath == 0)
{
- UNBLOCK_INPUT;
+ unblock_input ();
return spath;
}
/* On Altos 3068, getcwd can return @hostname/dir, so discard
npath++;
strcpy (pathname, npath);
free (spath); /* getcwd uses malloc */
- UNBLOCK_INPUT;
+ unblock_input ();
return pathname;
}
-#endif /* HAVE_GETWD */
-
-/*
- * Emulate rename using unlink/link. Note that this is
- * only partially correct. Also, doesn't enforce restriction
- * that files be of same type (regular->regular, dir->dir, etc).
- */
-
-#ifndef HAVE_RENAME
-
-int
-rename (const char *from, const char *to)
-{
- if (access (from, 0) == 0)
- {
- unlink (to);
- if (link (from, to) == 0)
- if (unlink (from) == 0)
- return (0);
- }
- return (-1);
-}
-
-#endif
-
-
-#if defined (HPUX) && !defined (HAVE_PERROR)
-
-/* HPUX curses library references perror, but as far as we know
- it won't be called. Anyway this definition will do for now. */
-
-void
-perror (void)
-{
-}
-#endif /* HPUX and not HAVE_PERROR */
-
-/*
- * This function will go away as soon as all the stubs fixed. (fnf)
- */
-
-void
-croak (char *badfunc)
-{
- printf ("%s not yet implemented\r\n", badfunc);
- reset_all_sys_modes ();
- exit (1);
-}
-
+#endif /* !defined (HAVE_GETWD) || defined (BROKEN_GETWD) */
#endif /* USG */
\f
/* Directory routines for systems that don't have them. */
int rtnval;
rtnval = emacs_close (dirp->dd_fd);
- xfree ((char *) dirp);
+ xfree (dirp);
return rtnval;
}
timespec[1] = mtime;
return fdutimens (fd, filename, timespec);
}
-\f
-/* mkdir and rmdir functions, for systems which don't have them. */
-
-#ifndef HAVE_MKDIR
-/*
- * Written by Robert Rother, Mariah Corporation, August 1985.
- *
- * If you want it, it's yours. All I ask in return is that if you
- * figure out how to do this in a Bourne Shell script you send me
- * a copy.
- * sdcsvax!rmr or rmr@uscd
- *
- * Severely hacked over by John Gilmore to make a 4.2BSD compatible
- * subroutine. 11Mar86; hoptoad!gnu
- *
- * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
- * subroutine didn't return EEXIST. It does now.
- */
-
-/*
- * Make a directory.
- */
-int
-mkdir (char *dpath, int dmode)
-{
- pid_t cpid;
- int status, fd;
- struct stat statbuf;
-
- if (stat (dpath, &statbuf) == 0)
- {
- errno = EEXIST; /* Stat worked, so it already exists */
- return -1;
- }
-
- /* If stat fails for a reason other than non-existence, return error */
- if (errno != ENOENT)
- return -1;
-
- synch_process_alive = 1;
- switch (cpid = fork ())
- {
-
- case -1: /* Error in fork */
- return (-1); /* Errno is set already */
-
- case 0: /* Child process */
- /*
- * Cheap hack to set mode of new directory. Since this
- * child process is going away anyway, we zap its umask.
- * FIXME, this won't suffice to set SUID, SGID, etc. on this
- * directory. Does anybody care?
- */
- status = umask (0); /* Get current umask */
- status = umask (status | (0777 & ~dmode)); /* Set for mkdir */
- fd = emacs_open ("/dev/null", O_RDWR, 0);
- if (fd >= 0)
- {
- dup2 (fd, 0);
- dup2 (fd, 1);
- dup2 (fd, 2);
- }
- execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
- _exit (-1); /* Can't exec /bin/mkdir */
-
- default: /* Parent process */
- wait_for_termination (cpid);
- }
-
- if (synch_process_death != 0 || synch_process_retcode != 0
- || synch_process_termsig != 0)
- {
- errno = EIO; /* We don't know why, but */
- return -1; /* /bin/mkdir failed */
- }
-
- return 0;
-}
-#endif /* not HAVE_MKDIR */
-
-#ifndef HAVE_RMDIR
-int
-rmdir (char *dpath)
-{
- int cpid, status, fd;
- struct stat statbuf;
-
- if (stat (dpath, &statbuf) != 0)
- {
- /* Stat just set errno. We don't have to */
- return -1;
- }
-
- synch_process_alive = 1;
- switch (cpid = fork ())
- {
-
- case -1: /* Error in fork */
- return (-1); /* Errno is set already */
-
- case 0: /* Child process */
- fd = emacs_open ("/dev/null", O_RDWR, 0);
- if (fd >= 0)
- {
- dup2 (fd, 0);
- dup2 (fd, 1);
- dup2 (fd, 2);
- }
- execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
- _exit (-1); /* Can't exec /bin/rmdir */
-
- default: /* Parent process */
- wait_for_termination (cpid);
- }
-
- if (synch_process_death != 0 || synch_process_retcode != 0
- || synch_process_termsig != 0)
- {
- errno = EIO; /* We don't know why, but */
- return -1; /* /bin/rmdir failed */
- }
-
- return 0;
-}
-#endif /* !HAVE_RMDIR */
-
\f
#ifndef HAVE_STRSIGNAL
char *
error ("tcsetattr() failed: %s", emacs_strerror (errno));
childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
- p->childp = childp2;
-
+ pset_childp (p, childp2);
}
#endif /* not DOS_NT */
\f
Lisp_Object
list_system_processes (void)
{
-#ifdef DARWIN_OS
+#if defined DARWIN_OS || defined __NetBSD__ || defined __OpenBSD__
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++)
{
-#ifdef DARWIN_OS
+#if defined DARWIN_OS || defined __NetBSD__
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
unsigned long long s = tval / hz;
unsigned long long frac = tval % hz;
int ns;
- EMACS_TIME t;
if (TYPE_MAXIMUM (time_t) < s)
time_overflow ();
ns = frac / hz_per_ns;
}
- EMACS_SET_SECS_NSECS (t, s, ns);
- return t;
+ return make_emacs_time (s, ns);
}
static Lisp_Object
get_up_time (void)
{
FILE *fup;
- EMACS_TIME up;
-
- EMACS_SET_SECS_NSECS (up, 0, 0);
+ EMACS_TIME up = make_emacs_time (0, 0);
- BLOCK_INPUT;
+ block_input ();
fup = fopen ("/proc/uptime", "r");
if (fup)
upfrac /= 10;
upfrac = min (upfrac, EMACS_TIME_RESOLUTION - 1);
}
- EMACS_SET_SECS_NSECS (up, upsec, upfrac);
+ up = make_emacs_time (upsec, upfrac);
}
fclose (fup);
}
- UNBLOCK_INPUT;
+ unblock_input ();
return up;
}
FILE *fdev = NULL;
char name[PATH_MAX];
- BLOCK_INPUT;
+ block_input ();
fdev = fopen ("/proc/tty/drivers", "r");
if (fdev)
}
fclose (fdev);
}
- UNBLOCK_INPUT;
+ unblock_input ();
return build_string (name);
}
FILE *fmem = NULL;
unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */
- BLOCK_INPUT;
+ block_input ();
fmem = fopen ("/proc/meminfo", "r");
if (fmem)
}
fclose (fmem);
}
- UNBLOCK_INPUT;
+ unblock_input ();
return retval;
}
char procbuf[1025], *p, *q;
int fd;
ssize_t nread;
- const char *cmd = NULL;
+ static char const default_cmd[] = "???";
+ const char *cmd = default_cmd;
+ int cmdsize = sizeof default_cmd - 1;
char *cmdline = NULL;
- ptrdiff_t cmdsize = 0, cmdline_size;
+ ptrdiff_t cmdline_size;
unsigned char c;
printmax_t proc_id;
int ppid, pgrp, sess, tty, tpgid, thcount;
/* 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);
}
else
q = NULL;
- if (cmd == NULL)
- {
- cmd = "???";
- cmdsize = 3;
- }
/* Command name is encoded in locale-coding-system; decode it. */
cmd_str = make_unibyte_string (cmd, cmdsize);
decoded_cmd = code_convert_string_norecord (cmd_str,
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);
- EMACS_GET_TIME (tnow);
+ tnow = current_emacs_time ();
telapsed = get_up_time ();
- EMACS_SUB_TIME (tboot, tnow, telapsed);
+ tboot = sub_emacs_time (tnow, telapsed);
tstart = time_from_jiffies (start, clocks_per_sec);
- EMACS_ADD_TIME (tstart, tboot, tstart);
+ tstart = add_emacs_time (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);
- EMACS_SUB_TIME (telapsed, tnow, tstart);
+ telapsed = sub_emacs_time (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)
if (emacs_read (fd, &ch, 1) != 1)
break;
c = ch;
- if (isspace (c) || c == '\\')
+ if (c_isspace (c) || c == '\\')
cmdline_size++; /* for later quoting, see below */
}
if (cmdline_size)
for (p = cmdline; p < cmdline + nread; p++)
{
/* Escape-quote whitespace and backslashes. */
- if (isspace (*p) || *p == '\\')
+ if (c_isspace (*p) || *p == '\\')
{
memmove (p + 1, p, nread - (p - cmdline));
nread++;
}
if (!cmdline_size)
{
- if (!cmd)
- cmd = "???";
- if (!cmdsize)
- cmdsize = strlen (cmd);
cmdline_size = cmdsize + 2;
cmdline = xmalloc (cmdline_size + 1);
- strcpy (cmdline, "[");
- strcat (strncat (cmdline, cmd, cmdsize), "]");
+ sprintf (cmdline, "[%.*s]", cmdsize, cmd);
}
emacs_close (fd);
/* Command line is encoded in locale-coding-system; decode it. */
/* 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);
static EMACS_TIME
timeval_to_EMACS_TIME (struct timeval t)
{
- EMACS_TIME e;
- EMACS_SET_SECS_NSECS (e, t.tv_sec, t.tv_usec * 1000);
- return e;
+ return make_emacs_time (t.tv_sec, t.tv_usec * 1000);
}
static Lisp_Object
-TIMELIST (struct timeval t)
+make_lisp_timeval (struct timeval t)
{
return make_lisp_time (timeval_to_EMACS_TIME (t));
}
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);
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 = Fcons (Fcons (Qcminflt, make_number (proc.ki_rusage_ch.ru_minflt)), attrs);
attrs = Fcons (Fcons (Qcmajflt, make_number (proc.ki_rusage_ch.ru_majflt)), attrs);
- attrs = Fcons (Fcons (Qutime, TIMELIST (proc.ki_rusage.ru_utime)), attrs);
- attrs = Fcons (Fcons (Qstime, TIMELIST (proc.ki_rusage.ru_stime)), attrs);
- EMACS_ADD_TIME (t,
- timeval_to_EMACS_TIME (proc.ki_rusage.ru_utime),
- timeval_to_EMACS_TIME (proc.ki_rusage.ru_stime));
- attrs = Fcons (Fcons (Qtime, TIMELIST (t)), attrs);
+ attrs = Fcons (Fcons (Qutime, make_lisp_timeval (proc.ki_rusage.ru_utime)),
+ 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));
+ attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs);
- attrs = Fcons (Fcons (Qcutime, TIMELIST (proc.ki_rusage_ch.ru_utime)), attrs);
- attrs = Fcons (Fcons (Qcstime, TIMELIST (proc.ki_rusage_ch.ru_utime)), attrs);
- EMACS_ADD_TIME (t,
- timeval_to_EMACS_TIME (proc.ki_rusage_ch.ru_utime),
- timeval_to_EMACS_TIME (proc.ki_rusage_ch.ru_stime));
- attrs = Fcons (Fcons (Qctime, TIMELIST (t)), attrs);
+ attrs = Fcons (Fcons (Qcutime,
+ make_lisp_timeval (proc.ki_rusage_ch.ru_utime)),
+ attrs);
+ 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));
+ attrs = Fcons (Fcons (Qctime, make_lisp_time (t)), attrs);
attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (proc.ki_numthreads)),
attrs);
attrs = Fcons (Fcons (Qpri, make_number (proc.ki_pri.pri_native)), attrs);
attrs = Fcons (Fcons (Qnice, make_number (proc.ki_nice)), attrs);
- attrs = Fcons (Fcons (Qstart, TIMELIST (proc.ki_start)), attrs);
+ attrs = Fcons (Fcons (Qstart, make_lisp_timeval (proc.ki_start)), attrs);
attrs = Fcons (Fcons (Qvsize, make_number (proc.ki_size >> 10)), attrs);
attrs = Fcons (Fcons (Qrss, make_number (proc.ki_rssize * pagesize >> 10)),
attrs);
- EMACS_GET_TIME (now);
- EMACS_SUB_TIME (t, now, timeval_to_EMACS_TIME (proc.ki_start));
- attrs = Fcons (Fcons (Qetime, TIMELIST (t)), attrs);
+ now = current_emacs_time ();
+ t = sub_emacs_time (now, timeval_to_EMACS_TIME (proc.ki_start));
+ attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs);
len = sizeof fscale;
if (sysctlbyname ("kern.fscale", &fscale, &len, NULL, 0) == 0)
decoded_comm =
(code_convert_string_norecord
- (make_unibyte_string (args, strlen (args)),
+ (build_unibyte_string (args),
Vlocale_coding_system, 0));
attrs = Fcons (Fcons (Qargs, decoded_comm), attrs);