Issue
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);
Solution
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.
Answered By - pilcrow