/*
 * Signal test; 
 * tests if sending a signal to the current process works
 * tests correct working of the user specified signal stack
 */

#include <signal.h>
#include <stdio.h>
#include <errno.h>

#define N 10000

char sstack[N];

volatile int kicked;

static int handler( int signr )
{
    printf(" IN HANDLER, signr=%d, sp= %x\n", signr, &signr );  
}

static int other_handler( int signr )
{
    int i;
    printf(" IN OTHER_HANDLER (pid= %d)\n", getpid());
    for (i=0; i<38; i++) {
        printf("pid= %2d: Fib(%d)= %d\n", getpid(), i, fib(i) );   
    }
    printf(" OUCH \n"); 
    kicked= 1; 
}


#define D(x) if (x) { printf("System call failure : " #x " errno=%d\n", errno); }


/* NOTE: sleep does not work yet under glibc,
  so use fibonacci as substitute */
int fib(i)
{
    if (i<2) { return 1; }
        else { return fib(i-1) + fib(i-2); }
}    

main() {
    
    struct sigaction act1, act2;
    stack_t   ss;
    sigset_t  sigset;
    int       pid;

    printf(" IN MAIN, sstack= %x sp= %x\n", sstack, &act1 );   

    act1.sa_handler= handler;
    act1.sa_flags  = 0;
    sigemptyset(&act1.sa_mask);
    sigemptyset(&sigset);

    act2.sa_handler= other_handler;
    act2.sa_flags  = 0;
    sigemptyset(&act2.sa_mask);

    ss.ss_sp   = sstack;
    ss.ss_size = N;
    ss.ss_flags= SS_ONSTACK;

    D( sigaction( SIGUSR1, &act1, 0) );
    D( sigaction( SIGUSR2, &act2, 0) );

    D( kill( getpid(), SIGUSR1) );

    D( sigaltstack(&ss,0) );

    kill( getpid(), SIGUSR1 );

    pid= fork();

    if (pid) {
           printf("pid= %2d: Fib(%d)= %d\n", getpid(), 37, fib(37) );   
           printf("pid= %2d: Fib(%d)= %d\n", getpid(), 38, fib(38) );   
           D( kill( pid, SIGUSR2 ) );
           printf(" PARENT TERMINATED\n");   
    } else {
           printf(" IN CHILD (pid= %d)\n", getpid());   
           D( sigsuspend(&sigset) );
           printf(" CHILD TERMINATED\n");   
    }
         
}
