Signals in C while using switchcontext - c

I've tried to implement a user-level thread library, using makecontext(), swapcontext() and getcontext() functions. I've read that a good practice is to use signals for schedule function (with a cyclic timer), but while a new thread is adding, block signals.
My problem is that: I can implement function to block signals, but it does not work when I use context switching.
void initSignals()
{
printf("initSignals\n");
act.sa_handler = schedule;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, &oact);
}
void blockSignals()
{
printf("blockSignals\n");
//sigset_t sig_mask;
sigemptyset(&sig_mask);
sigaddset(&sig_mask, SIGALRM);
sigprocmask(SIG_BLOCK, &sig_mask, NULL);
}
void unblockSignals()
{
printf("unblockSignals\n");
//sigset_t sig_mask;
sigemptyset(&sig_mask);
sigaddset(&sig_mask, SIGALRM);
sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
runTimer();
}
About sigset_t sig mask now it is global, but I tried to set it like a local variable too.
Moreover I tried to use another signals SIGPROF, SIGVTALRM, because my cyclic timer looks like:
void runTimer()
{
printf("runTimer\n");
it.it_interval.tv_sec = 1;
it.it_interval.tv_usec = 0;
it.it_value.tv_sec = 1;
it.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &it, NULL);
}
And itimer allow to use this 3 types of alarm...
So the question is: how to block signals while code is using context switching functions? Is it possible? Maybe another functions exist which can do that?
I thought that signals are being used for all processes, so I was surprised that it is not working...

Related

Exiting the p-thread cleanly using sigint as Interrupt

i am currently working on raspberry pi and interfacing an ADC with it. The ADC outputs the digital value continuously. The reading of the value and its processing is initiated and executed in a thread, therefore it should run forever. However in order to exit (for some reason) from the thread cleanly, I want to use SIGINT signal handler, which triggers an interrupt and changes the state of volatile variable.
The pseudo-program is as follows:
volatile sig_atomic_t exitThread = 0;
void signalHandler(){
exitThread = 1;
}
void SPI_Port0(){
//initialisation of functions and variables
while(!exitThread){
//do the work
}
if(exitThread){
pthread_exit(NULL);
}
}
void main(){
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = signalHandler;
sigaction(SIGINT, &sa, NULL);
pthread_t SPI0,SPI3;
pthread_create(&SPI0, NULL, SPI_Port0, NULL);
pthread_create(&SPI3, NULL, SPI_Port1, NULL);
pthread_join(SPI0, NULL);
pthread_join(SPI3, NULL);
//printing the results stored in arrays
//the arrays is declared global
}
there are two threads SPI_Port0 and SPI_Port1
doing the same implementation but on two different SPI ports, I want these two threads to exit when the CTRL + C is pressed. The problem i am facing is that, the whole program is exited.
Can someone point me in the right direction. Any help would be appreciated.
Modifications of variable and globals are not shared with child threads because they are other processes.
Fisrt of all you have to catch the signal :
Catch Ctrl-C in C
Then, in the signal interrupt, the child thread must be killed: For pthread, How to kill child thread from the main thread

Why is my signal handler not invoked more than once here?

jmp_buf functjmp;
void sigsegv_handler(int sig) {
sio_printf("Caught sigsegv!\n");
siglongjmp(functjmp, 2);
return;
}
void foo(unsigned val) {
assert(0);
sio_printf("entered!\n");
}
int main() {
struct sigaction action;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
sigaddset(&action.sa_mask, SIGSEGV);
action.sa_flags = SA_RESTART; /* Restart syscalls if possible */
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
sigset_t prev_mask;
sigprocmask(SIG_BLOCK, NULL, &prev_mask);
if (sigsetjmp(functjmp, 0) == 0) {
foo(*(unsigned *)0x8);
} {
sigprocmask(SIG_BLOCK, &prev_mask, NULL);
sio_printf("jump handled!\n");
foo(*(unsigned *)0x8);
}
sio_fprintf(stderr, "how did it come here?!\n");
}
I've been debugging this code using gdb, and I cannot figure out why the program will not handle the second SIGSEGV signal with my own handler, assuming no other signals were received or sent by the program? Any sio prefixed functions are async safe variants of the stdio counterparts.
Currently, I surmise it has to do with something I'm missing in my conception about returning from the signal handler, which longjmp doesn't do at all.
Short answer: normally not possible to resume after SIGSEGV for C program. You might get more mileage with C++.
Long Answer: See discussions in Coming back to life after Segmentation Violation
Assuming OK to take the risk of undefined behavior:
It is possible to re-enable SEGV. The core issue is that during signal handler, the code explicitly blocks the SEGV signal from being triggered (with the sigaddset). In addition, the default behavior (of signal handlers) is that during signal handling, the same signal processing will be deferred until the signal handler returns. In the OP code, the signal handler never returns (because of the siglongjmp)
Both issues can be addressed by changing the original code.
// Make sure all attributes are NULL.
struct sigaction action = {} ;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
// Not Needed:: sigaddset(&action.sa_mask, SIGSEGV);
// Add SA_NODEFER to disable the deferred processing of SIGSEGV.
action.sa_flags = SA_RESTART | SA_NODEFER ; /* Restart syscalls if possible */
// rest of code here
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
...

reset sigaction to default

In Android the bionic loader sets a default signal handler for every process on statrtup:
void debugger_init()
{
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = debugger_signal_handler;
act.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&act.sa_mask);
sigaction(SIGILL, &act, NULL);
sigaction(SIGABRT, &act, NULL);
sigaction(SIGBUS, &act, NULL);
sigaction(SIGFPE, &act, NULL);
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGSTKFLT, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
}
I would like to set it back to its default, meaning I want to ignore these signal and that the default handler will take place (CORE DUMP)
How do I revert the action performed ? I want to ignore all these as if the above function never was called
Read signal(7), sigaction(2) and perhaps signal(2).
You could call
signal(SIGILL, SIG_DFL);
signal(SIGABRT, SIG_DFL);
and so on early in your main (which is entered after dynamic loading)
You could also use sigaction with sa_handler set to SIG_DFL
Of course, things are more tricky if you want to default handle these signals before your main, e.g. in some static constructor!
I found it could lead unexpected behavior when mixed using sigaction and signal to set for one process.
From signal(2) posted above(wouldn't surprise me if this warning wasn't there 8 years ago):
WARNING: the behavior of signal() varies across UNIX versions,
and has also varied historically across different versions of
Linux. Avoid its use: use sigaction(2) instead.
Looking at https://docs.oracle.com/cd/E19455-01/806-5257/tlib-49639/index.html
int pthread_sigmask(int how, const sigset_t *new, sigset_t *old);
When the value of new is NULL, the value of how is not significant and the signal mask of the thread is unchanged. So, to inquire about currently blocked signals, assign a NULL value to the new argument.
So I guess you could use that to get the current sigmask and just wipe each one
sigset_t tempSet;
pthread_sigmask(SIG_SETMASK, NULL, &tempSet);
sigdelset(&tempSet, /*Signal you don't want to handle*/);
sigdelset(&tempSet, /*repeat for each signal*/);
pthread_sigmask(SIG_SETMASK, &tempSet, NULL);
It's pretty much the same thing with sigact to query the current action for a signal, from sigaction(2)
sigaction() can be called with a NULL second argument to query
the current signal handler.
It's not clear to me the ramifications of, in my case, having SIGKILL in the first call to sigaction
struct sigaction sigAct;
sigaction(SIGKILL, NULL, &sigAct);
sigAct.sa_handler = SIG_DFL; // Ensure default handling of Kill signal
sigaction(/*Signal you don't want to handle*/, &sigAct, NULL);
sigaction(/*repeat for each signal*/, &sigAct, NULL);
Using siggetmask is obsolete by sigprocmask, and sigprocmask is only for single threaded environments.

Signal handler for all signal

How can I register a signal handler for ALL signal, available on the running OS, using signal(3)?
My code looks like this:
void sig_handler(int signum)
{
printf("Received signal %d\n", signum);
}
int main()
{
signal(ALL_SIGNALS_??, sig_handler);
while (1) {
sleep(1);
};
return 0;
}
Most systems have a macro NSIG or _NSIG (the former would not be available in standards-conformance mode since it violates the namespace) defined in signal.h such that a loop for (i=1; i<_NSIG; i++) will walk all signals. Also, on POSIX systems that have signal masks, CHAR_BIT*sizeof(sigset_t) is an upper bound on the number of signals which you could use as a fallback if neither NSIG nor _NSIG is defined.
Signal handlers have to deal with reentrancy concerns and other problems. In practice, it's often more convenient to mask signals and then retrieve them from time to time. You can mask all signals (except SIGSTOP and SIGKILL, which you can't handle anyway) with this:
sigset_t all_signals;
sigfillset(&all_signals);
sigprocmask(SIG_BLOCK, &all_signals, NULL);
The code is slightly different if you're using pthreads. Call this in every thread, or (preferably) in the main thread before you create any others:
sigset_t all_signals;
sigfillset(&all_signals);
pthread_sigmask(SIG_BLOCK, &all_signals, NULL);
Once you've done that, you should periodically call sigtimedwait(2) like this:
struct timespec no_time = {0, 0};
siginfo_t result;
int rc = sigtimedwait(&all_signals, &result, &no_time);
If there is a signal pending, information about it will be placed in result and rc will be the signal number; if not, rc will be -1 and errno will be EAGAIN. If you're already calling select(2)/poll(2) (e.g. as part of some event-driven system), you may want to create a signalfd(2) instead and attach it to your event loop. In this case, you still need to mask the signals as shown above.

C : How to pause sigaction Timer

There is one function called test(), I want to call this function in every 30 seconds, Please find my implemented code snippet.
void init_sigaction(void) {
struct sigaction act;
act.sa_handler = test; //test()
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGPROF, &act, NULL);
}
void init_time(void) {
struct itimerval val;
val.it_value.tv_sec = 30; //Timer 30 Seconds
val.it_value.tv_usec = 0;
val.it_interval = val.it_value;
setitimer(ITIMER_PROF, &val, NULL);
}
int main()
{
/*Set the handler for the signal SIG to HANDLER */
signal(SIGINT, signal_handler);
init_sigaction();
init_time();
Some_other_function();
}
Now I am using some other function, and I want to pause sigaction timer until other function's execution. how can I implemented interrupt for pause?
Thanks,
From the manual page of setitimer:
A timer which is set to zero (it_value is zero or the timer expires and it_interval is zero) stops.
Call setitimer with zero times, and with a valid old_value argument to store the current values of the timer, so you can start it again later.
Edit:
How about something like this:
struct itimerval old_timer;
void pause_timer()
{
struct itimerval zero_timer = { 0 };
setitimer(ITIMER_PROF, &zero_time, &old_timer);
}
void resume_timer()
{
setitimer(ITIMER_PROF, &old_timer, NULL);
}
Note The code above is untested, and coded only by reading the manual page.
You could consider blocking some signals with e.g. the sigprocmask(2) system call.
However, I strongly recommend reading several times the signal(7) man page. Don't forget that a signal handler can happen any time (including at the worst possible time, e.g. during calls to fprintf or malloc...), so can only call directly or indirectly async-signal-safe functions; and a big lot of library functions are not in this small restricted set. A usual way is to set a volatile sig_atomic_t flag in the signal handler, and test for it outside.

Resources