diff options
Diffstat (limited to 'src/sysdep.c')
| -rw-r--r-- | src/sysdep.c | 165 |
1 files changed, 98 insertions, 67 deletions
diff --git a/src/sysdep.c b/src/sysdep.c index b84e6a4ea3a..0f16d1a7645 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -21,7 +21,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 21 | 21 | ||
| 22 | #define SYSTIME_INLINE EXTERN_INLINE | 22 | #define SYSTIME_INLINE EXTERN_INLINE |
| 23 | 23 | ||
| 24 | #include <signal.h> | 24 | #include <execinfo.h> |
| 25 | #include <stdio.h> | 25 | #include <stdio.h> |
| 26 | #include <setjmp.h> | 26 | #include <setjmp.h> |
| 27 | #ifdef HAVE_PWD_H | 27 | #ifdef HAVE_PWD_H |
| @@ -302,27 +302,34 @@ wait_for_termination_1 (pid_t pid, int interruptible) | |||
| 302 | termination of subprocesses, perhaps involving a kernel bug too, | 302 | termination of subprocesses, perhaps involving a kernel bug too, |
| 303 | but no idea what it is. Just as a hunch we signal SIGCHLD to see | 303 | but no idea what it is. Just as a hunch we signal SIGCHLD to see |
| 304 | if that causes the problem to go away or get worse. */ | 304 | if that causes the problem to go away or get worse. */ |
| 305 | sigsetmask (sigmask (SIGCHLD)); | 305 | sigset_t sigchild_mask; |
| 306 | sigemptyset (&sigchild_mask); | ||
| 307 | sigaddset (&sigchild_mask, SIGCHLD); | ||
| 308 | pthread_sigmask (SIG_SETMASK, &sigchild_mask, 0); | ||
| 309 | |||
| 306 | if (0 > kill (pid, 0)) | 310 | if (0 > kill (pid, 0)) |
| 307 | { | 311 | { |
| 308 | sigsetmask (SIGEMPTYMASK); | 312 | pthread_sigmask (SIG_SETMASK, &empty_mask, 0); |
| 309 | kill (getpid (), SIGCHLD); | 313 | kill (getpid (), SIGCHLD); |
| 310 | break; | 314 | break; |
| 311 | } | 315 | } |
| 312 | if (wait_debugging) | 316 | if (wait_debugging) |
| 313 | sleep (1); | 317 | sleep (1); |
| 314 | else | 318 | else |
| 315 | sigpause (SIGEMPTYMASK); | 319 | sigsuspend (&empty_mask); |
| 316 | #else /* not BSD_SYSTEM, and not HPUX version >= 6 */ | 320 | #else /* not BSD_SYSTEM, and not HPUX version >= 6 */ |
| 317 | #ifdef WINDOWSNT | 321 | #ifdef WINDOWSNT |
| 318 | wait (0); | 322 | wait (0); |
| 319 | break; | 323 | break; |
| 320 | #else /* not WINDOWSNT */ | 324 | #else /* not WINDOWSNT */ |
| 321 | sigblock (sigmask (SIGCHLD)); | 325 | sigset_t blocked; |
| 326 | sigemptyset (&blocked); | ||
| 327 | sigaddset (&blocked, SIGCHLD); | ||
| 328 | pthread_sigmask (SIG_BLOCK, &blocked, 0); | ||
| 322 | errno = 0; | 329 | errno = 0; |
| 323 | if (kill (pid, 0) == -1 && errno == ESRCH) | 330 | if (kill (pid, 0) == -1 && errno == ESRCH) |
| 324 | { | 331 | { |
| 325 | sigunblock (sigmask (SIGCHLD)); | 332 | pthread_sigmask (SIG_UNBLOCK, &blocked, 0); |
| 326 | break; | 333 | break; |
| 327 | } | 334 | } |
| 328 | 335 | ||
| @@ -456,11 +463,11 @@ child_setup_tty (int out) | |||
| 456 | #endif /* not MSDOS */ | 463 | #endif /* not MSDOS */ |
| 457 | 464 | ||
| 458 | 465 | ||
| 459 | /* Record a signal code and the handler for it. */ | 466 | /* Record a signal code and the action for it. */ |
| 460 | struct save_signal | 467 | struct save_signal |
| 461 | { | 468 | { |
| 462 | int code; | 469 | int code; |
| 463 | void (*handler) (int); | 470 | struct sigaction action; |
| 464 | }; | 471 | }; |
| 465 | 472 | ||
| 466 | static void save_signal_handlers (struct save_signal *); | 473 | static void save_signal_handlers (struct save_signal *); |
| @@ -618,8 +625,9 @@ save_signal_handlers (struct save_signal *saved_handlers) | |||
| 618 | { | 625 | { |
| 619 | while (saved_handlers->code) | 626 | while (saved_handlers->code) |
| 620 | { | 627 | { |
| 621 | saved_handlers->handler | 628 | struct sigaction action; |
| 622 | = (void (*) (int)) signal (saved_handlers->code, SIG_IGN); | 629 | emacs_sigaction_init (&action, SIG_IGN); |
| 630 | sigaction (saved_handlers->code, &action, &saved_handlers->action); | ||
| 623 | saved_handlers++; | 631 | saved_handlers++; |
| 624 | } | 632 | } |
| 625 | } | 633 | } |
| @@ -629,7 +637,7 @@ restore_signal_handlers (struct save_signal *saved_handlers) | |||
| 629 | { | 637 | { |
| 630 | while (saved_handlers->code) | 638 | while (saved_handlers->code) |
| 631 | { | 639 | { |
| 632 | signal (saved_handlers->code, saved_handlers->handler); | 640 | sigaction (saved_handlers->code, &saved_handlers->action, 0); |
| 633 | saved_handlers++; | 641 | saved_handlers++; |
| 634 | } | 642 | } |
| 635 | } | 643 | } |
| @@ -686,13 +694,17 @@ reset_sigio (int fd) | |||
| 686 | void | 694 | void |
| 687 | request_sigio (void) | 695 | request_sigio (void) |
| 688 | { | 696 | { |
| 697 | sigset_t unblocked; | ||
| 698 | |||
| 689 | if (noninteractive) | 699 | if (noninteractive) |
| 690 | return; | 700 | return; |
| 691 | 701 | ||
| 702 | sigemptyset (&unblocked); | ||
| 692 | #ifdef SIGWINCH | 703 | #ifdef SIGWINCH |
| 693 | sigunblock (sigmask (SIGWINCH)); | 704 | sigaddset (&unblocked, SIGWINCH); |
| 694 | #endif | 705 | #endif |
| 695 | sigunblock (sigmask (SIGIO)); | 706 | sigaddset (&unblocked, SIGIO); |
| 707 | pthread_sigmask (SIG_UNBLOCK, &unblocked, 0); | ||
| 696 | 708 | ||
| 697 | interrupts_deferred = 0; | 709 | interrupts_deferred = 0; |
| 698 | } | 710 | } |
| @@ -700,6 +712,8 @@ request_sigio (void) | |||
| 700 | void | 712 | void |
| 701 | unrequest_sigio (void) | 713 | unrequest_sigio (void) |
| 702 | { | 714 | { |
| 715 | sigset_t blocked; | ||
| 716 | |||
| 703 | if (noninteractive) | 717 | if (noninteractive) |
| 704 | return; | 718 | return; |
| 705 | 719 | ||
| @@ -708,10 +722,12 @@ unrequest_sigio (void) | |||
| 708 | return; | 722 | return; |
| 709 | #endif | 723 | #endif |
| 710 | 724 | ||
| 725 | sigemptyset (&blocked); | ||
| 711 | #ifdef SIGWINCH | 726 | #ifdef SIGWINCH |
| 712 | sigblock (sigmask (SIGWINCH)); | 727 | sigaddset (&blocked, SIGWINCH); |
| 713 | #endif | 728 | #endif |
| 714 | sigblock (sigmask (SIGIO)); | 729 | sigaddset (&blocked, SIGIO); |
| 730 | pthread_sigmask (SIG_BLOCK, &blocked, 0); | ||
| 715 | interrupts_deferred = 1; | 731 | interrupts_deferred = 1; |
| 716 | } | 732 | } |
| 717 | 733 | ||
| @@ -1470,20 +1486,16 @@ init_system_name (void) | |||
| 1470 | } | 1486 | } |
| 1471 | } | 1487 | } |
| 1472 | 1488 | ||
| 1473 | /* POSIX signals support - DJB */ | ||
| 1474 | /* Anyone with POSIX signals should have ANSI C declarations */ | ||
| 1475 | |||
| 1476 | sigset_t empty_mask; | 1489 | sigset_t empty_mask; |
| 1477 | 1490 | ||
| 1478 | #ifndef WINDOWSNT | 1491 | /* Store into *ACTION a signal action suitable for Emacs, with handler |
| 1479 | 1492 | HANDLER. */ | |
| 1480 | signal_handler_t | 1493 | void |
| 1481 | sys_signal (int signal_number, signal_handler_t action) | 1494 | emacs_sigaction_init (struct sigaction *action, signal_handler_t handler) |
| 1482 | { | 1495 | { |
| 1483 | struct sigaction new_action, old_action; | 1496 | sigemptyset (&action->sa_mask); |
| 1484 | sigemptyset (&new_action.sa_mask); | 1497 | action->sa_handler = handler; |
| 1485 | new_action.sa_handler = action; | 1498 | action->sa_flags = 0; |
| 1486 | new_action.sa_flags = 0; | ||
| 1487 | #if defined (SA_RESTART) | 1499 | #if defined (SA_RESTART) |
| 1488 | /* Emacs mostly works better with restartable system services. If this | 1500 | /* Emacs mostly works better with restartable system services. If this |
| 1489 | flag exists, we probably want to turn it on here. | 1501 | flag exists, we probably want to turn it on here. |
| @@ -1500,56 +1512,44 @@ sys_signal (int signal_number, signal_handler_t action) | |||
| 1500 | # if defined (BROKEN_SA_RESTART) || defined (SYNC_INPUT) | 1512 | # if defined (BROKEN_SA_RESTART) || defined (SYNC_INPUT) |
| 1501 | if (noninteractive) | 1513 | if (noninteractive) |
| 1502 | # endif | 1514 | # endif |
| 1503 | new_action.sa_flags = SA_RESTART; | 1515 | action->sa_flags = SA_RESTART; |
| 1504 | #endif | 1516 | #endif |
| 1505 | sigaction (signal_number, &new_action, &old_action); | ||
| 1506 | return (old_action.sa_handler); | ||
| 1507 | } | 1517 | } |
| 1508 | 1518 | ||
| 1509 | #endif /* WINDOWSNT */ | 1519 | #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD |
| 1510 | 1520 | pthread_t main_thread; | |
| 1511 | #ifndef __GNUC__ | ||
| 1512 | /* If we're compiling with GCC, we don't need this function, since it | ||
| 1513 | can be written as a macro. */ | ||
| 1514 | sigset_t | ||
| 1515 | sys_sigmask (int sig) | ||
| 1516 | { | ||
| 1517 | sigset_t mask; | ||
| 1518 | sigemptyset (&mask); | ||
| 1519 | sigaddset (&mask, sig); | ||
| 1520 | return mask; | ||
| 1521 | } | ||
| 1522 | #endif | 1521 | #endif |
| 1523 | 1522 | ||
| 1524 | /* I'd like to have these guys return pointers to the mask storage in here, | 1523 | /* If we are on the main thread, handle the signal SIG with HANDLER. |
| 1525 | but there'd be trouble if the code was saving multiple masks. I'll be | 1524 | Otherwise, redirect the signal to the main thread, blocking it from |
| 1526 | safe and pass the structure. It normally won't be more than 2 bytes | 1525 | this thread. POSIX says any thread can receive a signal that is |
| 1527 | anyhow. - DJB */ | 1526 | associated with a process, process group, or asynchronous event. |
| 1528 | 1527 | On GNU/Linux that is not true, but for other systems (FreeBSD at | |
| 1529 | sigset_t | 1528 | least) it is. */ |
| 1530 | sys_sigblock (sigset_t new_mask) | 1529 | void |
| 1530 | handle_on_main_thread (int sig, signal_handler_t handler) | ||
| 1531 | { | 1531 | { |
| 1532 | sigset_t old_mask; | 1532 | /* Preserve errno, to avoid race conditions with signal handlers that |
| 1533 | pthread_sigmask (SIG_BLOCK, &new_mask, &old_mask); | 1533 | might change errno. Races can occur even in single-threaded hosts. */ |
| 1534 | return (old_mask); | 1534 | int old_errno = errno; |
| 1535 | } | ||
| 1536 | 1535 | ||
| 1537 | sigset_t | 1536 | bool on_main_thread = true; |
| 1538 | sys_sigunblock (sigset_t new_mask) | 1537 | #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD |
| 1539 | { | 1538 | if (! pthread_equal (pthread_self (), main_thread)) |
| 1540 | sigset_t old_mask; | 1539 | { |
| 1541 | pthread_sigmask (SIG_UNBLOCK, &new_mask, &old_mask); | 1540 | sigset_t blocked; |
| 1542 | return (old_mask); | 1541 | sigemptyset (&blocked); |
| 1543 | } | 1542 | sigaddset (&blocked, sig); |
| 1543 | pthread_sigmask (SIG_BLOCK, &blocked, 0); | ||
| 1544 | pthread_kill (main_thread, sig); | ||
| 1545 | on_main_thread = false; | ||
| 1546 | } | ||
| 1547 | #endif | ||
| 1548 | if (on_main_thread) | ||
| 1549 | handler (sig); | ||
| 1544 | 1550 | ||
| 1545 | sigset_t | 1551 | errno = old_errno; |
| 1546 | sys_sigsetmask (sigset_t new_mask) | ||
| 1547 | { | ||
| 1548 | sigset_t old_mask; | ||
| 1549 | pthread_sigmask (SIG_SETMASK, &new_mask, &old_mask); | ||
| 1550 | return (old_mask); | ||
| 1551 | } | 1552 | } |
| 1552 | |||
| 1553 | 1553 | ||
| 1554 | #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST | 1554 | #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST |
| 1555 | static char *my_sys_siglist[NSIG]; | 1555 | static char *my_sys_siglist[NSIG]; |
| @@ -1564,6 +1564,10 @@ init_signals (void) | |||
| 1564 | { | 1564 | { |
| 1565 | sigemptyset (&empty_mask); | 1565 | sigemptyset (&empty_mask); |
| 1566 | 1566 | ||
| 1567 | #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD | ||
| 1568 | main_thread = pthread_self (); | ||
| 1569 | #endif | ||
| 1570 | |||
| 1567 | #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST | 1571 | #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST |
| 1568 | if (! initialized) | 1572 | if (! initialized) |
| 1569 | { | 1573 | { |
| @@ -1856,6 +1860,33 @@ snprintf (char *buf, size_t bufsize, char const *format, ...) | |||
| 1856 | } | 1860 | } |
| 1857 | #endif | 1861 | #endif |
| 1858 | 1862 | ||
| 1863 | /* If a backtrace is available, output the top lines of it to stderr. | ||
| 1864 | Do not output more than BACKTRACE_LIMIT or BACKTRACE_LIMIT_MAX lines. | ||
| 1865 | This function may be called from a signal handler, so it should | ||
| 1866 | not invoke async-unsafe functions like malloc. */ | ||
| 1867 | void | ||
| 1868 | emacs_backtrace (int backtrace_limit) | ||
| 1869 | { | ||
| 1870 | enum { BACKTRACE_LIMIT_MAX = 500 }; | ||
| 1871 | void *buffer[BACKTRACE_LIMIT_MAX + 1]; | ||
| 1872 | int bounded_limit = min (backtrace_limit, BACKTRACE_LIMIT_MAX); | ||
| 1873 | int npointers = backtrace (buffer, bounded_limit + 1); | ||
| 1874 | if (npointers) | ||
| 1875 | ignore_value (write (STDERR_FILENO, "\nBacktrace:\n", 12)); | ||
| 1876 | backtrace_symbols_fd (buffer, bounded_limit, STDERR_FILENO); | ||
| 1877 | if (bounded_limit < npointers) | ||
| 1878 | ignore_value (write (STDERR_FILENO, "...\n", 4)); | ||
| 1879 | } | ||
| 1880 | |||
| 1881 | #ifndef HAVE_NTGUI | ||
| 1882 | /* Using emacs_abort lets GDB return from a breakpoint here. */ | ||
| 1883 | void | ||
| 1884 | emacs_abort (void) | ||
| 1885 | { | ||
| 1886 | fatal_error_backtrace (SIGABRT, 10); | ||
| 1887 | } | ||
| 1888 | #endif | ||
| 1889 | |||
| 1859 | int | 1890 | int |
| 1860 | emacs_open (const char *path, int oflag, int mode) | 1891 | emacs_open (const char *path, int oflag, int mode) |
| 1861 | { | 1892 | { |