Signal takes a callback function as one of its arguments. To have variable behaviour I want to create a function within a function. This is my attempt so far:
typedef void (*sighandler_t)(int);
sighandler_t f(int pid) {
void sigintHandler(int sig) {
printf("Process %d", pid);
}
return sigintHandler
}
int main(void) {
...
if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
...
}
...
}
But, every time I send a SIGTSTP (Ctrl-z), I get a seg fault.
As a sidenote: any tips on how to debug seg faults in general would be really appreciated!
Your code compiles because it's syntactically correct and you're using compiler extensions; however, there are some fundamental issues with your code that might be leading to your segfault.
First, your signal handler code:
typedef void (*sighandler_t)(int);
sighandler_t f(int pid) {
void sigintHandler(int sig) {
printf("Process %d", pid);
}
return sigintHandler;
}
This is not standard C and even requires the -ftrampolines flag be specified on some versions of gcc to actually compile.
Your signal handler function itself has a few issues that need to be resolved:
sigintHandler is a nested function, thus when your signal handler function f returns by return sigintHandler;, you're returning a function pointer.
In your code, this compiles correctly because you have typedef void (*sighandler_t)(int);, which defines a function pointer type that can point to functions that have a void return type and take an int as a parameter, which your sigintHandler is defined as.
Instead, your signal handler function could be written simply as:
void sigintHandler(int sig) {
printf("Signal %d\n", sig);
}
In your main function, you have the following:
if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
// ....
}
Here it should be noted this as well has some issues. First, the signal function takes as its first parameter the signal number (usually a macro defined in the signal.h header) and as it's second argument a pointer to a function defined as void func_name(int sig).
To this, you are calling the function instead of passing it as a pointer.
*f(1) actually makes a call to f passing 1 as its parameter; instead, you would change it to the following:
if (signal(SIGTSTP, f) == SIG_ERR) {
// ....
}
But this should emit a warning/error since f is defined as returning a function pointer instead of void.
So to change the code to be compliant, you could just do the following:
#include <stdio.h>
#include <signal.h>
void sigintHandler(int sig) {
printf("Signal %d", sig);
}
int main(void) {
// ...
if (signal(SIGTSTP, sigintHandler) == SIG_ERR) {
// ...
}
// ...
return 0;
}
You stated however:
To have variable behaviour ...
This depends on what kind of variable nature you're intending, but if it's variable functions based on the signal, you can do something like the following:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sig_stop(int sig) {
printf("Process %d stop\n", getpid());
}
void sig_int(int sig) {
printf("Process %d interrupt\n", getpid());
}
int main(void) {
// ...
if (signal(SIGTSTP, sig_stop) == SIG_ERR) {
// ...
}
if (signal(SIGINT, sig_int) == SIG_ERR) {
// ...
}
// ...
return 0;
}
Or you could use a switch statement:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigHandler(int sig) {
printf("Process %d received %d\n", getpid(), sig);
switch (sig) {
case SIGTSTP:
// do stop code
break;
case SIGINT:
// do interupt code
break;
}
}
int main(void) {
// ...
if (signal(SIGTSTP, sigHandler) == SIG_ERR) {
// ...
}
if (signal(SIGINT, sigHandler) == SIG_ERR) {
// ...
}
// ...
return 0;
}
any tips on how to debug seg faults in general would be really appreciated!
First, understand what a segmentation fault is; then you can use a debugger like gdb to step through your code or inspect crash dumps to see where specifically the segfault is happening.
Hope that can help.
aint sure about what you are asking, but i can help you understand your segmentation fault.
when you call a function there are several things that are done.
push function arguments to stack
push return address to stack
jump to function address
function body
pop return address from stack
pop function arguments from stack.
when 1,2, 6 are done by the Calling scope.
As you know, signal is a void arguments hence the call (1) would push 0 arguments to the stack.
while the return (6) would pop your "unexistant" int from the stack and corrupt it.
somewhat solution
you can't have signal function with parameters,
what you can is:
you can read your global variables within the signal function. and therefore read the current state of the program.
you can sys_call to get your process_id, thread_id.
i wouldn't recommend but you can read your stack further to the previous scope and get it's local variables. With BIG Note that it won't be the function you set the signal at... but the function that was running at the moment of the signal.
Related
Trying to see how pthread works by running a simple program but I am getting segmentation fault (core dumped) at pthread_create
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
void* testfunc(void* arg) {
while (1) {
printf("testfunc");
}
}
int main(void) {
printf("helo\n");
if (pthread_create(NULL, NULL, &testfunc, NULL) != 0) {
perror("pthread failed to create\n");
}
while (1) {
printf("main function\n");
sleep(1000);
}
return 0;
}
What seems to be causing the problem? I am on Ubuntu 20.04 if that matters.
You can't pass NULL for pthread_create's first argument.
Before returning, a successful call to pthread_create() stores the ID of the new thread in the buffer pointed to by thread
Also, pthread_create doesn't set errno, so using perror makes no sense, at least not without some prep.
on error, it returns an error number, and the contents of *thread are undefined.
Fixed:
pthread_t thread;
if ( ( errno = pthread_create(&thread, NULL, &testfunc, NULL) ) != 0 ) {
perror("pthread failed to create\n");
}
...
pthread_join(thread, ...); // Normally.
Threads in c are very unforgiving. There are a few problems with your code that I can see.
First you might want to refer to the developer docs for p_thread. They are very well documented. What you currently have is a thread call but you are not pointing anything to that thread. This is why you are receiving the segmentation error. Meaning your program lost the pointer to that thread somewhere when it tried calling it. I suggest something like.
pthread_t thread;
int * argument = 5;
if(pthread_create(&thread,NULL, &testfunc, &argument) !=0){
// ^This is a pointer to your argument
// that you want to pass in
perror("pthread failed to create\n");
exit(1);
}
and your thread function will also need to be typecast from a void pointer into whatever you want it to return to work with. Then it needs to be cast back to a void pointer before is returned from the thread routine.
void* testfunc(void* arg){
int* testVar = (int *)arg;
// do some logic here
return (void *) testVar;
}
lastly you are responsible for your memory in C so you must kill the thread you created before exiting.
pthread_join(thread, NULL);
My number one suggestion is you watch some videos relating to it.
After figuring out the signature of the signal function, I modified the example given by https://en.cppreference.com/w/c/program/signal.
But why can't I call the function (the signal handler) returned by the signal, instead I can call it direclty ?
void (*signal( int sig, void (*handler) (int))) (int);
The signal function returns a pointer to function, which is void (*)(int).
Return value
Previous signal handler on success or SIG_ERR on failure (setting a signal handler can be disabled on some implementations).
#include <signal.h>
#include <stdio.h>
void signal_handler(int signal)
{
printf("hahahah\n");
}
int main(void)
{
void (*f1)(int);
f1 = signal(SIGINT, signal_handler);
f1(3); //Get signal SIGSEGV and failed
// signal_handler(3); //OK
raise(SIGINT);
}
I know it might look like a meaningless question, but the point is, f1 points to signal_handler, so calling f1(3) is just like calling signal_handler(3), I don't understand why the latter is ok but not the former, there should be not "tricks" that can make between these two calling function statments, I think.
There are at least 3 values that signal() can return that are not pointers to real functions:
SIG_DFL — typically ((void (*)(int))0)
SIG_IGN — typically ((void (*)(int))1)
SIG_ERR — typically ((void (*)(int))-1)
When a program starts, the signals are either in SIG_IGN or SIG_DFL mode; you can subsequently set them to another value.
When you call f1 = signal(SIGINT, signal_handler);, you get back one of SIG_DFL and SIG_IGN — and neither of those is a pointer to a callable function (even though their type is pointer to a function of the correct type).
In the following line:
f1 = signal(SIGINT, signal_handler);
f1 is assigned a previous signal handler (which is not signal_handler in the code) which may not be a pointer to a function that you can call with an int argument.
To achieve the effect you want to have define a second signal handler and assign it to f1 after the line mentioned above.
Something like this:
#include <signal.h>
#include <stdio.h>
void signal_handler2(int signal)
{
printf("hahahah2222\n");
}
void signal_handler(int signal)
{
printf("hahahah\n");
}
int main(void)
{
void (*f1)(int);
f1 = signal(SIGINT, signal_handler);
f1 = signal(SIGINT, signal_handler2);
f1(3); //Success
signal_handler2(3); //OK
raise(SIGINT);
}
Output:
hahahah
hahahah2222
hahahah2222
See Live Demo
I have a signal handling snippet but it is somehow malfunctioning on my Mac and virtual Linux box at koding.com but on my office Linux PC it is working..Can someone please tell me why..
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void my_isr(int n){
printf("Hello World");
signal(SIGINT, SIG_DFL);
}
int main(){
signal(SIGINT, my_isr);
printf("pid = %d\n", getpid());
while(1);
return 0;
}
When I am pressing Ctrl+C it is not printing Hello World on the first time but it is re-modifying the SIGINT signal action & hence it is exiting the program when I press Ctrl+C second time. Can someone explain me why?
You are not allowed to call every function in a signal handler.
Read signal(7). Only async signal safe functions can be called (directly or indirectly) from a signal handler, and printf is not such a function. If you really want to reliably "print" something from inside a signal handler (which I don't recommend), you can only use the low-level write(2) syscall (it is async signal safe).
So you've got undefined behavior. This explains why it is so bad.
The recommended way is to set a volatile sigatomic_t flag in your signal handler, and to test it outside of it (e.g. in your while loop...).
And you forgot to call fflush(3). You might be more lucky by ending your printf format string with \n since stdout is line-buffered!
Of course, changing your printf inside your signal handler is still UB, even with a \n, but very often it would appear to work.
Here is a conforming version of your program....
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
volatile sig_atomic_t got_signal;
void my_sigint_handler (int signum) {
if (signum == SIGINT) // this is always true!
got_signal = 1;
#define INTERRUPT_MESSAGE "Interrupted!\n"
write(STDOUT_FILENO, INTERRUPT_MESSAGE, strlen(INTERRUPT_MESSAGE));
};
int main(int argc, char**argv) {
struct sigaction act_int;
memset (&act_int, 0, sizeof(act_int));
act_int.sa_handler = my_sigint_handler;
if (sigaction(SIGINT, &act_int, NULL)) {
perror("sigaction"); exit(EXIT_FAILURE);
};
printf ("start %s pid %d\n", argv[0], (int)getpid());
while (!got_signal) {
};
printf ("ended %s after signal\n", argv[0]);
return 0;
}
A useful (and permissible) trick could be to write(2) a single byte -inside your signal handler- on a pipe(7) to self (you set up that pipe using pipe(2) early at program initialization), and in your event loop poll(2) the read end of that pipe.
printf is the culprit just use counter in handler and print outside handler its value it will work.
use sigaction instead of signal
Trying to implement process interruption handling using this function.
Following code running on OS X 10.10:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "sys/wait.h"
sig_t terminate(){
printf("Thanks for the fish!\n");
exit(EXIT_SUCCESS);
}
int main(int argc, const char * argv[]) {
signal(SIGINT, terminate());
while (1){
printf("P");
}
}
Problem is, that the terminate function is called immediately after running the program. Means, one does not see a single P, but only a line of Thanks for the fish!. What am I doing wrong?
Pass a function name instead of calling the function
signal(SIGINT, terminate );
Also signal takes the function pointer of type
void handler_function (int parameter);
Your signal handler does not match required prototype. You should redefine terminate() to take an int as parameter and return void.
That is,
void terminate(int sig) {
printf("Thanks for the fish!\n");
exit(EXIT_SUCCESS);
}
// ...
signal(SIGINT, terminate);
I am working in C language. I am trying to catch and process two different signals:
INT: when this signal is caught, action1 or action2 is triggered
QUIT: when this signal is caught, the INT signal action is switched (action1->action2 or action2->action1)
Default INT signal action is set to action1.
In my code,switchaction function is well triggered by QUIT signal, but has no effect on INT signal action :s
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
typedef void (*sighandler_t)(int);
sighandler_t prev_handler;
void action1(int n){
printf("First message\n");
}
void action2(int n){
printf("Second message\n");
}
void switchaction(int n){
printf("Switch action\n");
prev_handler=action2;
}
int main() {
prev_handler = action1;
printf("PID: %d\n", getpid());
prev_handler= signal(SIGINT,prev_handler);
signal(SIGQUIT,switchaction);
travail(); //This function never ends
}
Would you have any idea of what is wrong in my code ?
Thanks,
Yann
Your syscall
prev_handler= signal(SIGINT,prev_handler);
is setting the signal handler to the value of prev_handler variable at the moment you are executing the signal syscall. Changing (after) the value of prev_handler does not change the handling of SIGINT signal. In other words, signal (and most C calls) have a call by value semantics. If you call signal once, the kernel keep the same handler (till you call signal again with the same signal number, or till you call sigaction(2) etc...).
Read carefully (assuming you are on Linux) the signal(7) and signal(2) man pages.
I would instead define
volatile sig_atomic_t howhandle;
void switchaction(int n __attribute__((unused))) {
if (howhandle)
howhandle = 0;
else
howhandle = 1;
}
void handleint (int n) {
if (howhandle) action1(n); else action2(n);
}
and install just
signal(SIGINT, handleint);
signal(SIGQUIT, switchaction);
Also, notice that calling printf inside a handler is incorrect (because printf is not an async-signal-safe function, but you call it in action1, called by handleint...). Read again signal(7)
You should have some other volatile sig_atomic_t variables and test (and clear them) at appropriate places inside your travail working function, but set them only in your signal handlers. Setting a volatile sig_atomic_t variable is pretty much the only thing you can do reliably inside a signal handler.
If you accept Linux specific solutions learn more about signalfd(2) (and use also poll(2)...). Read also Advanced Linux Programming.