1

i am currently working on project involving the interfacing of an ADC with Ras.-Pi using SPI communication. In the project I am controlling the initialisation of SPI using a timer, which then initiates a signal handler. In the signal handler the SPI transmission takes place and value is being stored in a variable, this variabler i am accesing in a thread and storing the recieved value in an array. The code runs but the program never comes out of the signal handler. I want the handler to jump to the thread to store the recieved value everytime it processes a value. Can someone point me to something reliable.

void getSPIvalues(){ // A new Thread which runs parallel and get the values from ADC over SPI
    printf("inside thread function\n");
    timer_useconds(100, 1);
    spiValues[i] = rawData;
    printf("from thread, value = %d\n", spiValues[i]);
    i++;
}

void signalHandler(int sig){ 
    printf("inside handler function\n");
    PWMGenerate(0, 26, 2);  //Zyklus = 960 ns, Freuquency = 1,1 MHz, duty clycle= 8 %
    char data[2];
    bcm2835_spi_transfern(data, sizeof(data));
    rawData = (int)(data[0] << 8 | data[1]);
    bcm2835_gpio_write(PIN, LOW);
}

    //Handler Installation
    memset(&sa, 0, sizeof(sa));
    sigemptyset(&sa.sa_mask);
    sa.sa_handler = &signalHandler;
    sigaction(SIGVTALRM, &sa, NULL);
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • 9
    A signal handler should not do heavy duty work like it seems you are doing. In fact there are many functions, including `printf`, that should never be called in a signal handler. See https://man7.org/linux/man-pages/man7/signal-safety.7.html – kaylum May 13 '21 at 11:57
  • 1
    I recommend you to create a minimal working example that illustrates your issue. It would make easier to test to everybody and maybe even yourself would find out what it's happening on the process. – Ralequi May 13 '21 at 12:18
  • hi, the printf if is only used to check if the handler is called upon. Even if i omitt printf the program never comes out of the handler. – Kaustubh Bhargava May 13 '21 at 12:52
  • Can you show the code that arms the signal handler? – tofro May 13 '21 at 13:35
  • @tofro yes sure. I have used the virtual version of the alarm. //Handler Installation memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_handler = &signalHandler; sigaction(SIGVTALRM, &sa, NULL); – Kaustubh Bhargava May 13 '21 at 14:40
  • 3
    @KaustubhBhargava *Even if i omitt printf the program never comes out of the handler.* That's because you can't safely call functions like `bcm2835_spi_transfern()` or `bcm2835_gpio_write()` from within a signal handler. Full stop. You ***can't***. – Andrew Henle May 13 '21 at 15:26

1 Answers1

1

If I understand correctly, you want a "status update" every x useconds of process execution (rather than of wall clock time, as SIGVTALRM implies ITIMER_VIRTUAL to me).

The safest, simplest way to do this will be to accept a pending signal, instead of delivering that signal to a signal handler.

Before spawning any threads, use pthread_sigmask to SIG_BLOCK at least SIGVTALRM. All new threads will inherit that signal mask. Then, spawn your status thread, detached, which sets an intervalic virtual clock timer and loops, waiting to accept VTALRM:

static void *
my_status_thread(void *ignored) { // spawn me with VTALRM blocked
    sigset_t desired;             // for me and everyone else!

    sigemptyset(&desired);
    sigaddset(&desired, SIGVTALRM);

    set_itimer_virtual(100, 1);  // setitimer()

    while (1) {
        int s;
        (void)sigwait(&desired, &s);
        // we got VTALRM, pull the data
        PWMGenerate(...);
        ....
        printf("value is %d\n", ...);
    }

    return NULL; // not reached
}

Aside

It is possible to do this correctly with signal handlers.

It's quite nuanced, and the nuances matter. You should probably be aware that sigaction is preferred over signal and why. That signal disposition (a registered "handler" or "behavior") is a global process attribute, though signal delivery per se and signal masking are per-thread. That sig_atomic_t doesn't necessarily mean volatile, and why you'd care. That very, very few functions can be safely invoked within a signal handler. That sigemptyset(&sa.sa_mask) is, in my opinion, a bit cargo-culty, and you almost certainly want a full mask inside any consequential handlers.

Even then, it's just not worth it. Signal acceptance is a superior idiom to delivery: you react to signals when and where it is safe for you to do so.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
  • thank you very much for your answer. You are somwhat correct, i dont need status update every x useconds but i want to receive values from my ADC every x useconds. I want the reception to be interrupt controlled. Because the OS has limitations regarding Interrupts, so i went this way. The method you suggested looks good, i ll try this and let you know. – Kaustubh Bhargava May 14 '21 at 14:33