I'm experimenting with SIGINT. I basically want my program to start as soon as the user hits control-c. When this happens, I'm going to then get the program to make a pipe.
Now, I decided that when control-c is pressed in the signal handler it will call a function to create the pipe. Yet this is messing up. It's fine running a printf command but refuses to carry out the if statement until you press control-c again. Anyone able to assist?
Realistically, I want to disable control-C after it has been pressed once.
#include <stdio.h>
#include <signal.h>
void catchme(int signal);
void Setup();
int main()
{
if (signal(SIGINT, catchme) == SIG_ERR)
{
write(2, "Error catching signal C\n", 26);
}
printf("To begin, please press CTRL + C\n");
for(;;);
return 0;
}
void catchme(int signal)
{
write(1, "\n Caught Signal from Control C\n", 33);
Setup();
}
void Setup()
{
int firstPipe[2];
printf("Lets set up...\n");
if (pipe(firstPipe) < 0)
{
printf("Error creating pipe 1\n");
//abort program
}
else
{
printf("working so far");
}
}
You should get a debugger working. It would provide you with the answer to your question within seconds, and it's essential for trying to track down these kinds of problems. What seems very mystifying and unclear, when you're trying to interpret the output, will seem very easy when you're stepping through it, and you can see everything.
This will probably lead to pipe() not doing what you expect, you'll check errno, and presumably get a useful answer.
The commenter's advise about avoiding doing stuff in signal handlers is good, as it's not portable. However, most modern OSs are quite permissive, so I'm not sure if that's your problem in this case.
Related
I implemented a timer for a Linux user-space application using an old fashion way.
int main(){
//do some things
signal(SIGALRM, do_things);
alarm(1);
while(1) {
//other things
}
}
void do_things()
{
tic++;//global variable
printf("time: %d...", tic);
if (tic%30 == 0) {
printf("hha\n ");
do_calculation();
}
alarm(1);
}
It runs random times and stop print out anything, The application still alive but my timer seems gone. I have no idea where should I start to check. Any suggestion is appreciated.
Edit: Did some googling, Signal handlers are not supposed to contain "business logic" or make library calls such as printf.
All the signal handler should do is set a flag to be acted upon by non-interrupt code.
Though I still don't know what really happens to cause message disappear..
I'm a student new to C Programming and am not fully understanding how signal catching works, and in line with character device drivers. I'd appreciate some help but I need to state that this is for a project that is due in my first C Programming class. So I have not posted any direct code, only an example of my initial approach.
My project needs to accept a signal input and set that signal to a variable to pass to my character device driver. Another program I've written will need to access that variable's value such that when read, it performs a certain outcome. I've tried to run my control program (<name> &) but it quits immediately. I double check by entering ps into my command prompt and the process is gone.
Basically I need my control program to pause and wait for the signal to be received. Once received, if the signal matches it will set a variable to its value. Otherwise, if it is SIGTERM it will either end or pause(), where it will wait until another signal is received that meets another condition. Currently, when I compile and run it with & it simply runs and quits. Here is an example of my code:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
static int file_state; //variable to pass to the driver for recording
void sig_handler(int sig);
void sig_handler(int sig){
while(1){
if(sig == SIGRTMIN){
printf("SIG = SIGRTMIN\n");
file_state = 0;
}else if(sig == SIGRTMIN+1){
printf("SIG = SIGRTMIN1\n");
file_state = 1;
}else if(sig == SIGTERM){
printf("Exiting\n");
exit(0); //exit
}else{
printf("SIG = %i\n", sig);
pause(); //doesn't match, pause for next signal
}
}
}
int main(){
signal(SIGINT, sig_handler);
//return 0; //tried with and without
}
I'm waiting until this daemon receives a signal to put the device driver into a particular mode. I haven't entered any write() methods yet because I'm trying to take this one step at a time where I send a signal with kill() and the proper response is returned with printf().
My problem is that I can't seem to keep this in pause() mode while I'm waiting for a signal that breaks the if loop. What's worse (other than my lack of knowledge and programming) is that I can't even keep this daemon open long enough to attempt a signal send. Once I can get this to pause and receive the signal, I plan to use the system write() method to write my file_state variable to the /dev/<filename>, which will be cross-referenced in my executable.
How far off am I? This is the final part that (I believe) I'm stuck on and I can't figure out how this should be approached. I've looked online and about 95% of the examples that delve into this contain methods we haven't learned yet. And if not, the examples are more simplistic where they do not include passing a value to a character device driver for use when another program is using the driver.
Any help is greatly appreciated.
ETA
I've updated my code so now it stays open until a signal is received. Problem is that I want this to pause() and remain open until the SIGTERM signal is received, breaking the loop and ending the program. I can't seem to get the loop correct. Even entering a conditional int variable into the while() loop still is broken when any signal is received. Here is my updated code below:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
static int file_state; //variable to pass to the driver for recording
int keep_alive = 1; //added for conditional checking to keep the while
//loop open to receive more than one signal
void sig_handler(int sig);
void sig_handler(int sig){
if(sig == SIGRTMIN){
printf("SIG = SIGRTMIN\n");
file_state = 0;
}else if(sig == SIGRTMIN+1){
printf("SIG = SIGRTMIN1\n");
file_state = 1;
}else if(sig == SIGTERM){
keep_alive = 0;
}else{
}
}
int main(){
do{
signal(SIGINT, sig_handler);
pause(); //thought pausing here would help with waiting for a new signal
}while(keep_alive == 1); //keep looping until false
return 0; //tried with and without
}
I'm trying to figure out a method to keep this process and signal catching loop alive until a specific signal is received. I can't figure it out for the life of me.
ETA 2
Discovered my issue. I wasn't paying attention and fully understanding the signal() method. The first argument requires the exact signal you are attempting to catch. I was using SIGINT which I was understanding it to be a "class" of interrupts that you wanted to catch. And then in the signal_handler() function, you would specify which type of interrupt you were catching. But, it is actually looking to catch the exact signal you are interested in. So in my example code, I should have been using:
int main(){
if(signal(SIGRMIN, sig_handler) == SIG_ERR){
printf("can't catch SIGRMIN Signal.\n")
}
...
}
I'm going to update with my new script as an answer and if anyone thinks it should be done differently or have any constructive criticisms please let me know. Thanks again!
So I found my issue, and it is working now. Below is my fixed code that produces the correct response back to the terminal when caught. I've added a for() loop to catch any other signals I'm not worried about didn't stop my process, only SIGTERM will. Look forward to getting critiqued and why I would never want to do my approach.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
static int file_state; //variable to pass to the driver for recording
void sig_handler(int sig);
void sig_handler(int sig){
if(sig == SIGRTMIN){
printf("SIG = SIGRTMIN\n");
file_state = 0;
}else if(sig == SIGRTMIN+1){
printf("SIG = SIGRTMIN1\n");
file_state = 1;
}else if(sig == SIGTERM){
exit(0);
EXIT_SUCCESS;
}else{
printf("SIGNAL CAUGHT #%d\n", sig);
}
}
int main(){
if(signal(SIGRTMIN, sig_handler)==SIG_ERR){
printf("Unable to catch SIGRTMIN\n");
}
if(signal(SIGRTMIN+1, sig_handler)==SIG_ERR){
printf("Unable to catch SIGRTMIN+1\n");
}
if(signal(SIGTERM, sig_handler)==SIG_ERR){
printf("Unable to terminate process.\n");
}
//This for loop will catch all other signals except the un-catchable and
//other user-specified above signal #31.
int s;
for(s = 0; s < 32; s++){
signal(s, sig_handler);
}
while(1);
pause();
return 0;
}
There are 2 parts, 1st user space where generation and catching of signals occurs. This has nothing to do with kernel driver. Your code seems okay about it.
2nd is interacting with driver when signal has been caught. For char driver have a look at this link. You can simply write a value write(fd, 1, &buf); from user space program and implement corresponding write() in char driver.
I used the command "clear" in C language at infinite loop just for test and the kill signal does not stop it.
Why the program does not stop when i press Ctrl + C ?
#include <stdlib.h>
int main () {
while (1) {
system("clear");
}
return 0;
}
Killing clear will not help, because the infinite loop is in your own program. Kill that.
ControlC is only useful if you can get the system to pay attention. It sounds as if your terminal is too busy writing to the screen to do this.
From another terminal, run top and kill your program (which likely is near the top of the screen).
You could include a signal handler to 'catch' your CRTL-C input (which is SIGINT below) and then exit. Hopefully, this stub code will give you the idea. If not, I can provide a complete working example but would like to see you try first. :-)
#include <signal.h>
...
void stop (int signal) {
exit;
}
int main() {
signal(SIGINT, stop);
...
}
HTH
So I'm trying to call an alarm to display a message "still working.." every second.
I included signal.h.
Outside of my main I have my function: (I never declare/define s for int s)
void display_message(int s); //Function for alarm set up
void display_message(int s) {
printf("copyit: Still working...\n" );
alarm(1); //for every second
signal(SIGALRM, display_message);
}
Then, in my main
while(1)
{
signal(SIGALRM, display_message);
alarm(1); //Alarm signal every second.
That's in there as soon as the loop begins. But the program never outputs the 'still working...' message. What am I doing incorrectly? Thank you, ver much appreciated.
Signal handlers are not supposed to contain "business logic" or make library calls such as printf. See C11 ยง7.1.4/4 and its footnote:
Thus, a signal handler cannot, in general, call standard library functions.
All the signal handler should do is set a flag to be acted upon by non-interrupt code, and unblock a waiting system call. This program runs correctly and does not risk crashing, even if some I/O or other functionality were added:
#include <signal.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
volatile sig_atomic_t print_flag = false;
void handle_alarm( int sig ) {
print_flag = true;
}
int main() {
signal( SIGALRM, handle_alarm ); // Install handler first,
alarm( 1 ); // before scheduling it to be called.
for (;;) {
sleep( 5 ); // Pretend to do something. Could also be read() or select().
if ( print_flag ) {
printf( "Hello\n" );
print_flag = false;
alarm( 1 ); // Reschedule.
}
}
}
Move the calls to signal and alarm to just before your loop. Calling alarm over and over at high speed keeps resetting the alarm to be in one second from that point, so you never reach the end of that second!
For example:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void display_message(int s) {
printf("copyit: Still working...\n" );
alarm(1); //for every second
signal(SIGALRM, display_message);
}
int main(void) {
signal(SIGALRM, display_message);
alarm(1);
int n = 0;
while (1) {
++n;
}
return 0;
}
Do not call alarm() twice, just call it once in main() to initiate the callback, then once in display_message().
Try this code on Linux (Debian 7.8) :
#include <stdio.h>
#include <signal.h>
void display_message(int s); //Function for alarm set up
void display_message(int s)
{
printf("copyit: Still working...\n" );
alarm(1); //for every second
signal(SIGALRM, display_message);
}
int main()
{
signal(SIGALRM, display_message);
alarm(1); // Initial timeout setting
while (1)
{
pause();
}
}
The result will be the following one :
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
The alarm() call is for a one off signal.
To repeat an alarm, you have to call alarm() again each time the signal occurs.
Another issue, also, is that you're likely to get EINTR errors. Many system functions get interrupted when you receive a signal. This makes for much more complicated programming since many of the OS functions are affected.
In any event, the correct way to wait for the next SIGALRM is to use the pause() function. Something the others have not mentioned (instead they have tight loops, ugly!)
That being said, what you are trying to do would be much easier with a simple sleep() call as in:
// print a message every second (simplified version)
for(;;)
{
printf("My Message\n");
sleep(1);
}
and such a loop could appear in a separate thread. Then you don't need a Unix signal to implement the feat.
Note: The sleep() function is actually implemented using the same timer as the alarm() and it is clearly mentioned that you should not mix both functions in the same code.
sleep(3) may be implemented using SIGALRM; mixing calls to alarm() and sleep(3) is a bad idea.
(From Linux man alarm)
void alarm_handler(int)
{
alarm(1); // recurring alarm
}
int main(int argc, char *argv[])
{
signal(SIGALRM, alarm_handler);
alarm(1);
for(;;)
{
printf("My Message\n");
// ...do other work here if needed...
pause();
}
// not reached (use Ctrl-C to exit)
return 0;
}
You can create variations. For example, if you want the first message to happen after 1 second instead of immediately, move the pause() before the printf().
The "other work" comment supposes that your other work does not take more than 1 second.
It is possible to get the alarm signal on a specific thread if work is required in parallel, however, this can be complicated if any other timers are required (i.e. you can't easily share the alarm() timer with other functions.)
P.S. as mentioned by others, doing your printf() inside the signal handler is not a good idea at all.
There is another version where the alarm() is reset inside main() and the first message appears after one second and the loop runs for 60 seconds (1 minute):
void alarm_handler(int)
{
}
int main(int argc, char *argv[])
{
signal(SIGALRM, alarm_handler);
for(int seconds(0); seconds < 60; ++seconds)
{
alarm(1);
// ...do other work here if needed...
pause();
printf("My Message\n");
}
// reached after 1 minute
return 0;
}
Note that with this method, the time when the message will be printed is going to be skewed. The time to print your message is added to the clock before you restart the alarm... so it is always going to be a little over 1 second between each call. The other loop is better in that respect but it still is skewed. For a perfect (much better) timer, the poll() function is much better as you can specify when to wake up next. poll() can be used just and only with a timer. My Snap library uses that capability (look for the run() function, near the bottom of the file). In 2019. I moved that one .cpp file to the eventdispatcher library. The run() function is in the communicator.cpp file.
POSIX permits certain of its functions to be called from signal handling context, the async-signal safe functions, search for "async-sgnal safe" here. (These may be understood as "system calls" rather than library calls). Notably, this includes write(2).
So you could do
void
display_message (int s) {
static char const working_message [] = "copyit: Still working...\n";
write (1, working_message, sizeof working_message - sizeof "");
alarm(1); /* for every second */
}
By the way, precise periodic alarms are better implemented using setitimer(2),
since these will not be subject to drift. Retriggering the alarm via software, as done here, will unavoidably accumulate error over time because of the time spent executing the software as well as scheduling latencies.
In POSIX sigaction(2) superceedes signal(2) for good reason:
the original Unix signal handling model was simple. In particular,
a signal handler was reset to its original "deposition" (e.g., terminate
the process) once it was fired. You would have to re-associate
SIGALRM with display_message() by calling signal() just before
calling alarm() in display_message().
An even more important reason for using sigaction(2) is the
SA_RESTART flag. Normally, system calls are interrupted when
a signal handler is invoked. I.e., when then signal handler returns,
the system call returns an error indication (often -1) and errno is
set to EINTR, interrupted system call. (One reason for this
is to be able to use SIGALRM to effect time outs, another is
to have a higher instance, such as a user, to "unblock" the
current process by sending it a signal, e.g.,
SIGINT by pressing control-C at the terminal).
In your case, you want signal handling to be transparent
to the rest of the code, so you would set the SA_RESTART flag
when invoking sigaction(2). This means the kernel should
restart the interrupted system call automatically.
ooga is correct that you keep reloading the alarm so that it will never go off. This works. I just put a sleep in here so you don't keep stepping on yourself in the loop but you might want to substitute something more useful depending on where you are headed with this.
void display_message(int s)
{
printf("copyit: Still working...\n" );
// alarm(1); //for every second
// signal(SIGALRM, display_message);
}
int main(int argc, char *argv[])
{
int ret;
while(1)
{
signal(SIGALRM, display_message);
alarm(1);
if ((ret = sleep(3)) != 0)
{
printf("sleep was interrupted by SIGALRM\n");
}
}
return (0);
}
So i need to write an whileloop for a program that's supposed to prompt the user with this:
char vector[10];
while(????){
print("Write a number");
scanf("%s",vector);
}
printf("Goodbye");
The program is supposed to print goodbye and close when the user presses ctrl+c.
Im pretty sure I cant use putchar in this case?
#include <windows.h>
#include <stdio.h>
static end_flag = 0;
BOOL WINAPI controlHandler(DWORD type){
if(type == CTRL_C_EVENT){
end_flag = 1;
return TRUE;
}
return FALSE;
}
int main(){
char vector[10];
if (!SetConsoleCtrlHandler(controlHandler, TRUE)) {
fprintf(stderr, "Failed SetConsoleCtrlHandler");
return -1;
}
while(!end_flag){
printf("Write a number ");
scanf("%s",vector);
}
printf("Goodbye");
return 0;
}
CTRL+Z version
#include <stdio.h>
int main(){
char vector[10];
while(1){
printf("Write a number ");
if(scanf("%s", vector)==EOF)//press CTRL+Z
break;
}
printf("Goodbye");
return 0;
}
see https://superuser.com/questions/214239/whats-the-command-prompts-equivalent-to-cygwins-ctrlz:
Depends on what you mean by "quit something"; within Windows cmd:
Ctrl+Z sends the EOF character, which could terminate a process if
you're providing input, but otherwise will probably do nothing.
Ctrl+C normally sends SIGINT to the foreground process, which should
terminate it, but programs can respond however they like - ie, they
can catch the signal but then ignore it. The command can also be
remapped to other jobs (such that for a specific program it doesn't
really send a signal) or ignored entirely.
Ctrl+Break always sends SIGBREAK, which again should terminate the
process, but unlike Ctrl+C cannot be remapped, but can still be
ignored. This is probably what you need.
I think this might be what you're looking for:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms683242%28v=vs.85%29.aspx
Post similar to this one on Stack Overflow:
Catch Ctrl-C in C
You might want to check it out. Cheers!