Revision c0532a76 cpus.c

b/cpus.c
34 34

  
35 35
#include "cpus.h"
36 36
#include "compatfd.h"
37
#ifdef CONFIG_LINUX
38
#include <sys/prctl.h>
39
#endif
37 40

  
38 41
#ifdef SIGRTMIN
39 42
#define SIG_IPI (SIGRTMIN+4)
......
41 44
#define SIG_IPI SIGUSR1
42 45
#endif
43 46

  
47
#ifndef PR_MCE_KILL
48
#define PR_MCE_KILL 33
49
#endif
50

  
44 51
static CPUState *next_cpu;
45 52

  
46 53
/***********************************************************/
......
498 505
    }
499 506
}
500 507

  
508
static void sigbus_reraise(void)
509
{
510
    sigset_t set;
511
    struct sigaction action;
512

  
513
    memset(&action, 0, sizeof(action));
514
    action.sa_handler = SIG_DFL;
515
    if (!sigaction(SIGBUS, &action, NULL)) {
516
        raise(SIGBUS);
517
        sigemptyset(&set);
518
        sigaddset(&set, SIGBUS);
519
        sigprocmask(SIG_UNBLOCK, &set, NULL);
520
    }
521
    perror("Failed to re-raise SIGBUS!\n");
522
    abort();
523
}
524

  
525
static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
526
                           void *ctx)
527
{
528
#if defined(TARGET_I386)
529
    if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr))
530
#endif
531
        sigbus_reraise();
532
}
533

  
501 534
static void qemu_kvm_eat_signal(CPUState *env, int timeout)
502 535
{
503 536
    struct timespec ts;
504 537
    int r, e;
505 538
    siginfo_t siginfo;
506 539
    sigset_t waitset;
540
    sigset_t chkset;
507 541

  
508 542
    ts.tv_sec = timeout / 1000;
509 543
    ts.tv_nsec = (timeout % 1000) * 1000000;
510 544

  
511 545
    sigemptyset(&waitset);
512 546
    sigaddset(&waitset, SIG_IPI);
547
    sigaddset(&waitset, SIGBUS);
513 548

  
514
    qemu_mutex_unlock(&qemu_global_mutex);
515
    r = sigtimedwait(&waitset, &siginfo, &ts);
516
    e = errno;
517
    qemu_mutex_lock(&qemu_global_mutex);
549
    do {
550
        qemu_mutex_unlock(&qemu_global_mutex);
518 551

  
519
    if (r == -1 && !(e == EAGAIN || e == EINTR)) {
520
        fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
521
        exit(1);
522
    }
552
        r = sigtimedwait(&waitset, &siginfo, &ts);
553
        e = errno;
554

  
555
        qemu_mutex_lock(&qemu_global_mutex);
556

  
557
        if (r == -1 && !(e == EAGAIN || e == EINTR)) {
558
            fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
559
            exit(1);
560
        }
561

  
562
        switch (r) {
563
        case SIGBUS:
564
#ifdef TARGET_I386
565
            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr))
566
#endif
567
                sigbus_reraise();
568
            break;
569
        default:
570
            break;
571
        }
572

  
573
        r = sigpending(&chkset);
574
        if (r == -1) {
575
            fprintf(stderr, "sigpending: %s\n", strerror(e));
576
            exit(1);
577
        }
578
    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
523 579
}
524 580

  
525 581
static void qemu_kvm_wait_io_event(CPUState *env)
......
640 696

  
641 697
    pthread_sigmask(SIG_BLOCK, NULL, &set);
642 698
    sigdelset(&set, SIG_IPI);
699
    sigdelset(&set, SIGBUS);
643 700
    r = kvm_set_signal_mask(env, &set);
644 701
    if (r) {
645 702
        fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
......
650 707
static sigset_t block_io_signals(void)
651 708
{
652 709
    sigset_t set;
710
    struct sigaction action;
653 711

  
654 712
    /* SIGUSR2 used by posix-aio-compat.c */
655 713
    sigemptyset(&set);
......
660 718
    sigaddset(&set, SIGIO);
661 719
    sigaddset(&set, SIGALRM);
662 720
    sigaddset(&set, SIG_IPI);
721
    sigaddset(&set, SIGBUS);
663 722
    pthread_sigmask(SIG_BLOCK, &set, NULL);
664 723

  
724
    memset(&action, 0, sizeof(action));
725
    action.sa_flags = SA_SIGINFO;
726
    action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
727
    sigaction(SIGBUS, &action, NULL);
728
    prctl(PR_MCE_KILL, 1, 1, 0, 0);
729

  
665 730
    return set;
666 731
}
667 732

  

Also available in: Unified diff