root/src/tests/system/libroot/posix/signal_test.cpp
/*
 * Copyright 2007, Axel Dörfler, axeld@pinc-software.de.
 * Distributed under the terms of the MIT License.
 */


#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


#if defined(__BEOS__) && !defined(__HAIKU__)
typedef void (*sighandler_t)(int);
#       define SIGSTKSZ         16384
#       define SA_ONESHOT       0
#       define SA_ONSTACK       0
#       define SA_RESTART       0
#       define ualarm(usec, interval) alarm(1)
#endif

#if !defined(__USE_GNU)
// sighandler is a GNU extension. This matches the check
// in signal.h.  We may want to use posix sigaction though
// in the future which is posix
typedef void (*sighandler_t)(int);
#endif


const void* kUserDataMagic = (void *)0x12345678;

static char sAlternateStack[SIGSTKSZ];


bool
is_alternate(void* pointer)
{
        return (char*)pointer > &sAlternateStack[0]
                && (char*)pointer <= &sAlternateStack[0] + SIGSTKSZ;
}


void
sigHandler(int signal, void *userData, vregs *regs)
{
#if defined(__BEOS__) || defined(__HAIKU__)
        if (userData != kUserDataMagic)
                fprintf(stderr, "FAILED: user data not correct: %p\n", userData);
#endif

        printf("signal handler called with signal %i on %s stack\n",
                signal, is_alternate(&signal) ? "alternate" : "standard");
}


void
wait_for_key()
{
        char buffer[100];
        if (fgets(buffer, sizeof(buffer), stdin) == NULL
                || buffer[0] == 'q') {
                if (errno == EINTR)
                        puts("interrupted");
                else
                        exit(0);
        }
}

int
main()
{
        puts("-- 1 (should block) --");

        struct sigaction newAction;
        newAction.sa_handler = (sighandler_t)sigHandler;
        newAction.sa_mask = 0;
        newAction.sa_flags = SA_ONESHOT | SA_ONSTACK | SA_RESTART;
#if defined(__BEOS__) || defined(__HAIKU__)
        newAction.sa_userdata = (void*)kUserDataMagic;
#endif
        sigaction(SIGALRM, &newAction, NULL);

        ualarm(10000, 0);
        wait_for_key();

        puts("-- 2 (does not block, should call handler twice) --");

        newAction.sa_flags = 0;
        sigaction(SIGALRM, &newAction, NULL);

        ualarm(0, 50000);
        wait_for_key();
        wait_for_key();

        ualarm(0, 0);

        puts("-- 3 (alternate stack, should block) --");

#if defined(__BEOS__) && !defined(__HAIKU__)
        set_signal_stack(sAlternateStack, SIGSTKSZ);
#else
        stack_t newStack;
        newStack.ss_sp = sAlternateStack;
        newStack.ss_size = SIGSTKSZ;
        newStack.ss_flags = 0;
        if (sigaltstack(&newStack, NULL) != 0)
                fprintf(stderr, "sigaltstack() failed: %s\n", strerror(errno));
#endif

        newAction.sa_flags = SA_RESTART | SA_ONSTACK;
        sigaction(SIGALRM, &newAction, NULL);

        ualarm(10000, 0);
        wait_for_key();

        puts("-- end --");
        return 0;
}