X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/8f50130c565eaf0ad7c49e4ad044c3291ecdfa71..fb39b937b0628f4592b07d0aa61a41cf696abd30:/src/sysdep.c diff --git a/src/sysdep.c b/src/sysdep.c index bd8a102044..f4e055c31a 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1,5 +1,5 @@ /* Interfaces to system-dependent kernel and library entries. - Copyright (C) 1985-1988, 1993-1995, 1999-2011 + Copyright (C) 1985-1988, 1993-1995, 1999-2012 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -18,10 +18,11 @@ You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include -#include -#include + +#define SYSTIME_INLINE EXTERN_INLINE + +#include #include -#include #ifdef HAVE_PWD_H #include #include @@ -30,41 +31,42 @@ along with GNU Emacs. If not, see . */ #include #include +#include #include #include +#include #include "lisp.h" #include "sysselect.h" #include "blockinput.h" +#ifdef BSD_SYSTEM +#include +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#include +#endif + #ifdef WINDOWSNT #define read sys_read #define write sys_write #include -#ifndef NULL -#define NULL 0 -#endif #endif /* not WINDOWSNT */ #include #include #include -#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 #endif #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */ -#include -#include "dosfns.h" #include "msdos.h" #include #endif @@ -101,25 +103,13 @@ extern char *getwd (char *); #include "syssignal.h" #include "systime.h" -#ifdef HAVE_UTIME_H -#include -#endif - -#ifndef HAVE_UTIMES -#ifndef HAVE_STRUCT_UTIMBUF -/* We want to use utime rather than utimes, but we couldn't find the - structure declaration. We'll use the traditional one. */ -struct utimbuf { - long actime; - long modtime; -}; -#endif -#endif static int emacs_get_tty (int, struct emacs_tty *); static int emacs_set_tty (int, struct emacs_tty *, int); -#if defined TIOCNOTTY || defined USG5 || defined CYGWIN -static void croak (char *) NO_RETURN; + +/* 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. */ @@ -157,7 +147,7 @@ get_current_dir_name (void) #endif ) { - buf = (char *) malloc (strlen (pwd) + 1); + buf = malloc (strlen (pwd) + 1); if (!buf) return NULL; strcpy (buf, pwd); @@ -166,7 +156,7 @@ get_current_dir_name (void) else { size_t buf_size = 1024; - buf = (char *) malloc (buf_size); + buf = malloc (buf_size); if (!buf) return NULL; for (;;) @@ -181,7 +171,7 @@ get_current_dir_name (void) return NULL; } buf_size *= 2; - buf = (char *) realloc (buf, buf_size); + buf = realloc (buf, buf_size); if (!buf) return NULL; } @@ -190,7 +180,7 @@ get_current_dir_name (void) else { /* We need MAXPATHLEN here. */ - buf = (char *) malloc (MAXPATHLEN + 1); + buf = malloc (MAXPATHLEN + 1); if (!buf) return NULL; if (getwd (buf) == NULL) @@ -289,10 +279,6 @@ init_baud_rate (int fd) -/* Set nonzero to make following function work under dbx - (at least for bsd). */ -int wait_debugging EXTERNALLY_VISIBLE; - #ifndef MSDOS static void @@ -300,41 +286,24 @@ wait_for_termination_1 (pid_t pid, int 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 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; } @@ -462,11 +431,11 @@ child_setup_tty (int out) #endif /* not MSDOS */ -/* 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 *); @@ -512,7 +481,7 @@ sys_subshell (void) 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 @@ -530,7 +499,7 @@ sys_subshell (void) 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++] = '/'; @@ -624,8 +593,9 @@ save_signal_handlers (struct save_signal *saved_handlers) { 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++; } } @@ -635,118 +605,80 @@ restore_signal_handlers (struct save_signal *saved_handlers) { while (saved_handlers->code) { - signal (saved_handlers->code, saved_handlers->handler); + sigaction (saved_handlers->code, &saved_handlers->action, 0); saved_handlers++; } } -#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) { - if (noninteractive) - return; +#ifdef USABLE_SIGIO + sigset_t blocked; -#if 0 /* XXX What's wrong with blocking SIGIO under X? */ - if (x_display_list) + if (noninteractive) 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 */ - /* Getting and setting emacs_tty structures. */ @@ -865,7 +797,7 @@ init_sys_modes (struct tty_display_info *tty_out) 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); @@ -1359,7 +1291,7 @@ init_system_name (void) 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 @@ -1375,7 +1307,7 @@ init_system_name (void) 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. @@ -1476,85 +1408,134 @@ init_system_name (void) } } -/* 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; +} #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST static char *my_sys_siglist[NSIG]; @@ -1564,17 +1545,70 @@ 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 @@ -1602,9 +1636,7 @@ init_signals (void) # ifdef SIGEMT sys_siglist[SIGEMT] = "Emulation trap"; # endif -# ifdef SIGFPE sys_siglist[SIGFPE] = "Arithmetic exception"; -# endif # ifdef SIGFREEZE sys_siglist[SIGFREEZE] = "SIGFREEZE"; # endif @@ -1614,12 +1646,8 @@ init_signals (void) # 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 @@ -1668,9 +1696,7 @@ init_signals (void) # ifdef SIGSAK sys_siglist[SIGSAK] = "Secure attention"; # endif -# ifdef SIGSEGV sys_siglist[SIGSEGV] = "Segmentation violation"; -# endif # ifdef SIGSOUND sys_siglist[SIGSOUND] = "Sound completed"; # endif @@ -1683,9 +1709,7 @@ init_signals (void) # 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 @@ -1730,6 +1754,129 @@ init_signals (void) # 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 } #ifndef HAVE_RANDOM @@ -1770,19 +1917,37 @@ init_signals (void) #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. @@ -1800,21 +1965,6 @@ get_random (void) 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 @@ -1858,6 +2008,46 @@ snprintf (char *buf, size_t bufsize, char const *format, ...) } #endif +/* 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)); + } +} + +#ifndef HAVE_NTGUI +void +emacs_abort (void) +{ + terminate_due_to_signal (SIGABRT, 10); +} +#endif + int emacs_open (const char *path, int oflag, int mode) { @@ -1935,11 +2125,10 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte) { 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 @@ -1991,7 +2180,7 @@ emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE]) * under error conditions. */ -#ifndef HAVE_GETWD +#if !defined (HAVE_GETWD) || defined (BROKEN_GETWD) #ifndef MAXPATHLEN /* In 4.1, param.h fails to define this. */ @@ -2004,11 +2193,11 @@ getwd (char *pathname) 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 @@ -2017,83 +2206,11 @@ getwd (char *pathname) 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 */ - -/* - * Gettimeofday. Simulate as much as possible. Only accurate - * to nearest second. Emacs doesn't use tzp so ignore it for now. - * Only needed when subprocesses are defined. - */ - -#ifndef HAVE_GETTIMEOFDAY -#ifdef HAVE_TIMEVAL - -int -gettimeofday (struct timeval *tp, struct timezone *tzp) -{ - extern long time (long); - - tp->tv_sec = time ((long *)0); - tp->tv_usec = 0; - if (tzp != 0) - tzp->tz_minuteswest = -1; - return 0; -} - -#endif -#endif /* !HAVE_GETTIMEOFDAY && HAVE_TIMEVAL */ - -/* - * 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 */ /* Directory routines for systems that don't have them. */ @@ -2110,7 +2227,7 @@ closedir (DIR *dirp /* stream from opendir */) int rtnval; rtnval = emacs_close (dirp->dd_fd); - xfree ((char *) dirp); + xfree (dirp); return rtnval; } @@ -2118,147 +2235,44 @@ closedir (DIR *dirp /* stream from opendir */) #endif /* HAVE_DIRENT_H */ -int -set_file_times (const char *filename, EMACS_TIME atime, EMACS_TIME mtime) -{ -#ifdef HAVE_UTIMES - struct timeval tv[2]; - tv[0] = atime; - tv[1] = mtime; - return utimes (filename, tv); -#else /* not HAVE_UTIMES */ - struct utimbuf utb; - utb.actime = EMACS_SECS (atime); - utb.modtime = EMACS_SECS (mtime); - return utime (filename, &utb); -#endif /* not HAVE_UTIMES */ -} - -/* 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) +/* 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) { - 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; + struct timeval tv; + tv.tv_sec = t.tv_sec; + tv.tv_usec = t.tv_nsec / 1000; - synch_process_alive = 1; - switch (cpid = fork ()) + if (t.tv_nsec % 1000 != 0) { - - 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 */ + if (tv.tv_usec < 999999) + tv.tv_usec++; + else if (tv.tv_sec < TYPE_MAXIMUM (time_t)) + { + tv.tv_sec++; + tv.tv_usec = 0; + } } - return 0; + return tv; } -#endif /* not HAVE_MKDIR */ -#ifndef HAVE_RMDIR +/* Set the access and modification time stamps of FD (a.k.a. FILE) to be + ATIME and MTIME, respectively. + FD must be either negative -- in which case it is ignored -- + or a file descriptor that is open on FILE. + If FD is nonnegative, then FILE can be NULL. */ int -rmdir (char *dpath) +set_file_times (int fd, const char *filename, + EMACS_TIME atime, EMACS_TIME mtime) { - 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; + struct timespec timespec[2]; + timespec[0] = atime; + timespec[1] = mtime; + return fdutimens (fd, filename, timespec); } -#endif /* !HAVE_RMDIR */ - #ifndef HAVE_STRSIGNAL char * @@ -2489,8 +2503,7 @@ serial_configure (struct Lisp_Process *p, 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 */ @@ -2530,6 +2543,52 @@ list_system_processes (void) return proclist; } +#elif defined BSD_SYSTEM + +Lisp_Object +list_system_processes (void) +{ +#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}; +#endif + size_t len; + struct kinfo_proc *procs; + size_t i; + + struct gcpro gcpro1; + Lisp_Object proclist = Qnil; + + if (sysctl (mib, 3, NULL, &len, NULL, 0) != 0) + return proclist; + + procs = xmalloc (len); + if (sysctl (mib, 3, procs, &len, NULL, 0) != 0) + { + xfree (procs); + return proclist; + } + + GCPRO1 (proclist); + len /= sizeof (struct kinfo_proc); + for (i = 0; i < len; i++) + { +#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 + } + UNGCPRO; + + xfree (procs); + + return proclist; +} + /* The WINDOWSNT implementation is in w32.c. The MSDOS implementation is in dosfns.c. */ #elif !defined (WINDOWSNT) && !defined (MSDOS) @@ -2543,60 +2602,78 @@ list_system_processes (void) #endif /* !defined (WINDOWSNT) */ #ifdef GNU_LINUX -static void -time_from_jiffies (unsigned long long tval, long hz, - time_t *sec, unsigned *usec) -{ - unsigned long long ullsec; - - *sec = tval / hz; - ullsec = *sec; - tval -= ullsec * hz; - /* Careful: if HZ > 1 million, then integer division by it yields zero. */ - if (hz <= 1000000) - *usec = tval * 1000000 / hz; +static EMACS_TIME +time_from_jiffies (unsigned long long tval, long hz) +{ + unsigned long long s = tval / hz; + unsigned long long frac = tval % hz; + int ns; + + 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; else - *usec = tval / (hz / 1000000); + { + /* 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)); + ns = frac / hz_per_ns; + } + + return make_emacs_time (s, ns); } static Lisp_Object ltime_from_jiffies (unsigned long long tval, long hz) { - time_t sec; - unsigned usec; - - time_from_jiffies (tval, hz, &sec, &usec); - - return list3 (make_number ((sec >> 16) & 0xffff), - make_number (sec & 0xffff), - make_number (usec)); + EMACS_TIME t = time_from_jiffies (tval, hz); + return make_lisp_time (t); } -static void -get_up_time (time_t *sec, unsigned *usec) +static EMACS_TIME +get_up_time (void) { FILE *fup; + EMACS_TIME up = make_emacs_time (0, 0); - *sec = *usec = 0; - - BLOCK_INPUT; + block_input (); fup = fopen ("/proc/uptime", "r"); if (fup) { - double uptime, idletime; + unsigned long long upsec, upfrac, idlesec, idlefrac; + int upfrac_start, upfrac_end, idlefrac_start, idlefrac_end; - /* The numbers in /proc/uptime use C-locale decimal point, but - we already set ourselves to the C locale (see `fixup_locale' - in emacs.c). */ - if (2 <= fscanf (fup, "%lf %lf", &uptime, &idletime)) + if (fscanf (fup, "%llu.%n%llu%n %llu.%n%llu%n", + &upsec, &upfrac_start, &upfrac, &upfrac_end, + &idlesec, &idlefrac_start, &idlefrac, &idlefrac_end) + == 4) { - *sec = uptime; - *usec = (uptime - *sec) * 1000000; + if (TYPE_MAXIMUM (time_t) < upsec) + { + upsec = TYPE_MAXIMUM (time_t); + upfrac = EMACS_TIME_RESOLUTION - 1; + } + else + { + int upfraclen = upfrac_end - upfrac_start; + for (; upfraclen < LOG10_EMACS_TIME_RESOLUTION; upfraclen++) + upfrac *= 10; + for (; LOG10_EMACS_TIME_RESOLUTION < upfraclen; upfraclen--) + upfrac /= 10; + upfrac = min (upfrac, EMACS_TIME_RESOLUTION - 1); + } + up = make_emacs_time (upsec, upfrac); } fclose (fup); } - UNBLOCK_INPUT; + unblock_input (); + + return up; } #define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff) @@ -2608,7 +2685,7 @@ procfs_ttyname (int rdev) FILE *fdev = NULL; char name[PATH_MAX]; - BLOCK_INPUT; + block_input (); fdev = fopen ("/proc/tty/drivers", "r"); if (fdev) @@ -2640,7 +2717,7 @@ procfs_ttyname (int rdev) } fclose (fdev); } - UNBLOCK_INPUT; + unblock_input (); return build_string (name); } @@ -2650,7 +2727,7 @@ procfs_get_total_memory (void) FILE *fmem = NULL; unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */ - BLOCK_INPUT; + block_input (); fmem = fopen ("/proc/meminfo", "r"); if (fmem) @@ -2669,7 +2746,7 @@ procfs_get_total_memory (void) } fclose (fmem); } - UNBLOCK_INPUT; + unblock_input (); return retval; } @@ -2685,9 +2762,11 @@ system_process_attributes (Lisp_Object pid) 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; @@ -2696,9 +2775,7 @@ system_process_attributes (Lisp_Object pid) unsigned long long u_time, s_time, cutime, cstime, start; long priority, niceness, rss; unsigned long minflt, majflt, cminflt, cmajflt, vsize; - time_t sec; - unsigned usec; - EMACS_TIME tnow, tstart, tboot, telapsed; + EMACS_TIME tnow, tstart, tboot, telapsed, us_time; double pcpu, pmem; Lisp_Object attrs = Qnil; Lisp_Object cmd_str, decoded_cmd, tem; @@ -2715,17 +2792,17 @@ system_process_attributes (Lisp_Object 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); @@ -2751,11 +2828,6 @@ system_process_attributes (Lisp_Object pid) } 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, @@ -2820,36 +2892,19 @@ system_process_attributes (Lisp_Object pid) 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); - get_up_time (&sec, &usec); - EMACS_SET_SECS (telapsed, sec); - EMACS_SET_USECS (telapsed, usec); - EMACS_SUB_TIME (tboot, tnow, telapsed); - time_from_jiffies (start, clocks_per_sec, &sec, &usec); - EMACS_SET_SECS (tstart, sec); - EMACS_SET_USECS (tstart, usec); - EMACS_ADD_TIME (tstart, tboot, tstart); - attrs = Fcons (Fcons (Qstart, - list3 (make_number - ((EMACS_SECS (tstart) >> 16) & 0xffff), - make_number - (EMACS_SECS (tstart) & 0xffff), - make_number - (EMACS_USECS (tstart)))), - attrs); + tnow = current_emacs_time (); + telapsed = get_up_time (); + tboot = sub_emacs_time (tnow, telapsed); + tstart = time_from_jiffies (start, clocks_per_sec); + 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); - attrs = Fcons (Fcons (Qetime, - list3 (make_number - ((EMACS_SECS (telapsed) >> 16) & 0xffff), - make_number - (EMACS_SECS (telapsed) & 0xffff), - make_number - (EMACS_USECS (telapsed)))), - attrs); - time_from_jiffies (u_time + s_time, clocks_per_sec, &sec, &usec); - pcpu = (sec + usec / 1000000.0) / (EMACS_SECS (telapsed) + EMACS_USECS (telapsed) / 1000000.0); + 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) + / EMACS_TIME_TO_DOUBLE (telapsed)); if (pcpu > 1.0) pcpu = 1.0; attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); @@ -2873,7 +2928,7 @@ system_process_attributes (Lisp_Object pid) 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) @@ -2897,7 +2952,7 @@ system_process_attributes (Lisp_Object pid) 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++; @@ -2910,14 +2965,9 @@ system_process_attributes (Lisp_Object pid) } 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. */ @@ -2980,17 +3030,17 @@ system_process_attributes (Lisp_Object 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); @@ -3030,33 +3080,20 @@ system_process_attributes (Lisp_Object pid) Qcstime Are they available? */ - attrs = Fcons (Fcons (Qtime, - list3 (make_number (pinfo.pr_time.tv_sec >> 16), - make_number (pinfo.pr_time.tv_sec & 0xffff), - make_number (pinfo.pr_time.tv_nsec))), - attrs); - - attrs = Fcons (Fcons (Qctime, - list3 (make_number (pinfo.pr_ctime.tv_sec >> 16), - make_number (pinfo.pr_ctime.tv_sec & 0xffff), - make_number (pinfo.pr_ctime.tv_nsec))), - attrs); - + 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, - list3 (make_number (pinfo.pr_start.tv_sec >> 16), - make_number (pinfo.pr_start.tv_sec & 0xffff), - make_number (pinfo.pr_start.tv_nsec))), - 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 encoded as a fixed point 16 bit number in [0 ... 1]. */ - attrs = Fcons (Fcons (Qpcpu, (pinfo.pr_pctcpu * 100.0) / (double)0x8000), attrs); - attrs = Fcons (Fcons (Qpmem, (pinfo.pr_pctmem * 100.0) / (double)0x8000), 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, @@ -3077,6 +3114,192 @@ system_process_attributes (Lisp_Object pid) return attrs; } +#elif defined __FreeBSD__ + +static EMACS_TIME +timeval_to_EMACS_TIME (struct timeval t) +{ + return make_emacs_time (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)); +} + +Lisp_Object +system_process_attributes (Lisp_Object pid) +{ + int proc_id; + int pagesize = getpagesize (); + int npages; + int fscale; + struct passwd *pw; + struct group *gr; + char *ttyname; + size_t len; + char args[MAXPATHLEN]; + EMACS_TIME t, now; + + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID}; + struct kinfo_proc proc; + size_t proclen = sizeof proc; + + struct gcpro gcpro1, gcpro2; + Lisp_Object attrs = Qnil; + Lisp_Object decoded_comm; + + CHECK_NUMBER_OR_FLOAT (pid); + CONS_TO_INTEGER (pid, int, proc_id); + mib[3] = proc_id; + + if (sysctl (mib, 4, &proc, &proclen, NULL, 0) != 0) + return attrs; + + GCPRO2 (attrs, decoded_comm); + + attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (proc.ki_uid)), attrs); + + block_input (); + pw = getpwuid (proc.ki_uid); + 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 (); + gr = getgrgid (proc.ki_svgid); + 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); + + attrs = Fcons (Fcons (Qcomm, decoded_comm), attrs); + { + char state[2] = {'\0', '\0'}; + switch (proc.ki_stat) + { + case SRUN: + state[0] = 'R'; + break; + + case SSLEEP: + state[0] = 'S'; + break; + + case SLOCK: + state[0] = 'D'; + break; + + case SZOMB: + state[0] = 'Z'; + break; + + case SSTOP: + state[0] = 'T'; + break; + } + attrs = Fcons (Fcons (Qstate, build_string (state)), attrs); + } + + attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (proc.ki_ppid)), 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 (); + ttyname = proc.ki_tdev == NODEV ? NULL : devname (proc.ki_tdev, S_IFCHR); + unblock_input (); + if (ttyname) + attrs = Fcons (Fcons (Qtty, build_string (ttyname)), attrs); + + attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (proc.ki_tpgid)), attrs); + attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (proc.ki_rusage.ru_minflt)), attrs); + attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (proc.ki_rusage.ru_majflt)), 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, 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, + 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, 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); + + 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) + { + double pcpu; + fixpt_t ccpu; + len = sizeof ccpu; + if (sysctlbyname ("kern.ccpu", &ccpu, &len, NULL, 0) == 0) + { + pcpu = (100.0 * proc.ki_pctcpu / fscale + / (1 - exp (proc.ki_swtime * log ((double) ccpu / fscale)))); + attrs = Fcons (Fcons (Qpcpu, make_fixnum_or_float (pcpu)), attrs); + } + } + + len = sizeof npages; + if (sysctlbyname ("hw.availpages", &npages, &len, NULL, 0) == 0) + { + double pmem = (proc.ki_flag & P_INMEM + ? 100.0 * proc.ki_rssize / npages + : 0); + attrs = Fcons (Fcons (Qpmem, make_fixnum_or_float (pmem)), attrs); + } + + mib[2] = KERN_PROC_ARGS; + len = MAXPATHLEN; + if (sysctl (mib, 4, args, &len, NULL, 0) == 0) + { + int i; + for (i = 0; i < len; i++) + { + if (! args[i] && i < len - 1) + args[i] = ' '; + } + + decoded_comm = + (code_convert_string_norecord + (build_unibyte_string (args), + Vlocale_coding_system, 0)); + + attrs = Fcons (Fcons (Qargs, decoded_comm), attrs); + } + + UNGCPRO; + return attrs; +} + /* The WINDOWSNT implementation is in w32.c. The MSDOS implementation is in dosfns.c. */ #elif !defined (WINDOWSNT) && !defined (MSDOS)