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);
Related
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'm trying to make a C program that can continue running also after a CTRL+C.
I wrote this:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void acceptCommands();
void sighandle_int(int sign)
{
//system("^C;./a.out"); *out:* ^Csh: ^C: command not found
// how to protect here the app from being killed?
}
int main(int argc, char **argv)
{
signal(SIGINT, sighandle_int);
acceptCommands();
return 0;
}
how can i do?
Thank you
I'm trying to make a C program that can continue running also after a CTRL+C. ? when the process receives CTRL+C you set the handler for that using sigaction() and in that handler you can specify whether to continue or ignore or whatever you want.
May be you want like this
void sighandle_int(int sign) {
/*when process receives SIGINT this isr will be called,
here you can specify whether you want to continue or ignore,
by signal handler again */
signal(SIGINT,SIG_IGN);
//or
signal(SIGINT,sighandle_int);
}
Meanwhile use sigaction() instead of signal() as told here What is the difference between sigaction and signal?
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.
I am writing my own simple shell. One thing which I need to do is to control the SIGINT signal by remaining in the shell and just printing the prompt on a fresh line when ctrl+c is pressed. Currently, I have been able to handle the signal and the shell simply prints ^C after the prompt. However, the cursor remains on the same line. What I would like to do instead is have the shell print ^C after the prompt, move onto the next line and then print a fresh prompt.
I have found this question, which addresses the exact same issue. The problem with mine is that my main calls another function where the prompt loop is run. I have tried many different ways to try to implement the solution given on the link above, in both the main and the prompt loop function, but all with no luck. Here is my code so far:
Main.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "MyShell.h"
void ctrl_C_handler();
int main(int argc, char **argv) {
signal(SIGINT, ctrl_C_handler);
my_shell_loop();
return EXIT_SUCCESS;
}
void ctrl_C_handler() {
//Catches the SIGINT signal fine without anything happening in this function
//I cannot figure out how to have MyShell print a fresh prompt on a new line
//after ctrl+C is pressed
}
MyShellLoop.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "MyShell.h"
char *get_time();
void my_shell_loop() {
char *line;
char **args;
int status;
char *prompt = (char *) malloc(17);
do {
strcpy(prompt, get_time());
strcat(prompt, " # ");
printf("%s", prompt);
line = read_command();
args = split_command(line);
status = execute_command(args);
free(line);
free(args);
} while (status);
free(prompt);
}
EDIT
Using:
void ctrl_C_handler() {
signal(SIGINT, ctrl_C_handler);
printf("\n");
my_shell_loop();
}
acts as desired the first time ctrl+c is pressed, but then acts as it did before for any further times it is pressed.
signal attaches a handler only for the first appropriate signal that is received. After that invocation, the handler is detached. A common method is to have the handler reattach itself as in int foo() { signal(SIGINT, &foo); do_the_stuff(); }.
However, signal is non-portable. POSIX recommends using sigaction instead.
Code in question first (minimized case):
#include <stdio.h>
#include <signal.h>
int counter = 0;
void react_to_signal(int n) {
fprintf(stderr, "Caught!\n");
counter++;
}
int main(int argc, char** argv) {
signal(SIGINFO, react_to_signal);
while (1) {
printf("%d\n", counter);
}
return 0;
}
I run the code, it loops as it should, printing out 0. Then in another shell..
kill -s SIGINFO <pid_of_my_process>
Signal is delivered, c is incremented .. but the fprintf doesn't happen.
Why is this so? In what environment/context does handler code run? Where can I read up on this?
In short: you cannot safely use printf within a signal handler.
There's a list of authorized functions in signal handler's man page. There is not fprintf in it.
That's because this function is not reentrant, mainly because it can use malloc and free.
See this post for a detailed explanation.
You may need to fflush stderr to get the message to write before the program exits.