I want to write some code that takes input from stdin, and prints the input on the next line, until a signal is sent, the signal being SIGINT in this case. So far I have this code which just prints a message when SIGINT is sent:
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
bool signalSent = false;
void flag(int signal) {
signalSent = true;
}
int main(int argc, char** argv) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = flag;
sa.sa_flags = SA_RESTART;
sigaction(SIGINT, &sa, 0);
while (true) {
while (!signalSent) {
usleep(500000);
}
printf("signal sent\n");
signalSent = false;
}
return 0;
}
I tried using fgets() to get the input from stdin and print to stdout, but when I enter ^C (SIGINT) I have to press enter, but I want it to send the message ("signal sent\n"); as soon as it is pressed like the code I currently have. Code using fgets():
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
bool signalSent = false;
void flag(int signal) {
signalSent = true;
}
int main(int argc, char** argv) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = flag;
sa.sa_flags = SA_RESTART;
sigaction(SIGINT, &sa, 0);
while (true) {
while (!signalSent) {
char buffer[80];
char* t = fgets(buffer, sizeof(buffer), stdin);
printf("%s", t);
fflush(stdout);
}
printf("signal sent\n");
signalSent = false;
}
return 0;
}
Output from code:
For reference I want my output to look like the picture below. Im very new to using signals in C as well.
As detailed in the manual pages for sigaction(2) and signal(7), the SA_RESTART flag causes certain system calls, including read(2), to automatically restart after the signal handler has ended.
It seems that you do not want this behaviour.
fgets is implemented by way of read, and can fail for the same reasons it can. Without SA_RESTART, while waiting on input from a "slow" device (this includes terminals), these functions will set errno to EINTR if interrupted by a signal.
Note that what can and cannot be done in a signal handler is complicated.
Consider using sig_atomic_t objects, declared as volatile, for these types of flags.
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static volatile sig_atomic_t signal_sent = 0;
void flag(int signal) {
(void) signal;
signal_sent = 1;
}
int main(void) {
struct sigaction sa = { .sa_handler = flag };
sigaction(SIGINT, &sa, 0);
while (!signal_sent) {
char buffer[80];
if (fgets(buffer, sizeof buffer, stdin))
printf("%s", buffer);
else if (errno == EINTR && signal_sent) {
puts("signal sent");
signal_sent = 0;
} else
return 1;
}
}
Example of running this program (^D to terminate):
$ ./a.out
foo
foo
^Csignal sent
^Csignal sent
bar
bar
hello wor^Csignal sent
Related
I am having a parent process play that creates a fork and runs foo using execl
Code for play.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
if (fork() == 0) {
execl("./foo", "", NULL);
} else {
wait(0);
write(STDOUT_FILENO, "in parent after waiting", 5);
}
printf("outside everything");
return 0;
}
Code for foo.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void signal_handler() {
write(STDOUT_FILENO, "\nBye!\n", 6);
exit(1);
}
int main() {
struct sigaction sa;
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
while (1) {
printf("Wasting time...%d \n", getpid());
sleep(1);
}
return 0;
}
My questions are,
Why aren't the print statements after the wait(0) statement executed?
Why isn't the signal handler in the child process triggered when Ctrl + C?
You should ensure that the sa_flags and sa_mask fields of struct sigaction are set. You can initialize them — struct sigaction sa = { 0 }; will probably do the job. Or you can use sigemptyset(&sa.sa_mask); and sa.sa_flags = 0; to assign values. Or you can set them to some non-zero value. Not setting sa_flags means you've no idea what operation you requested. You also need a signal handler in play.c. You need to ignore SIGINT before the fork(), then in the child re-enable the signal before executing foo. The write() in the parent does not print much; it may once have printed "\nBar!\n" or something.
Here's some working code.
play.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
struct sigaction sa = { 0 };
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, NULL);
if (fork() == 0)
{
sa.sa_handler = SIG_DFL;
sigaction(SIGINT, &sa, NULL);
execl("./foo", "", NULL);
exit(1);
}
else
{
wait(0);
printf("in parent after waiting\n");
}
printf("outside everything\n");
return 0;
}
foo.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void signal_handler(int signum)
{
char message[] = "\nBye (XX)\n";
message[6] = signum / 10 + '0';
message[7] = signum % 10 + '0';
write(STDOUT_FILENO, message, sizeof(message) - 1);
exit(1);
}
int main(void)
{
struct sigaction sa = { 0 };
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
while (1)
{
printf("Wasting time...%d \n", getpid());
sleep(1);
}
return 0;
}
Example output
$ play
Wasting time...11383
Wasting time...11383
Wasting time...11383
Wasting time...11383
^C
Bye (02)
in parent after waiting
outside everything
$
I'm trying to do something simple with alarms, however the printf is never executing after I do the alarm, why's that?
#include <stdio.h>
#include <signal.h>
int main() {
alarm(3);
printf("Hello...\n");
alarm(6);
while(1);
printf("Hello2\n");
}
I want hello and hello2 to be printed, only hello is being printed for now
You didn't specify a handler for SIGALRM, and its default behavior (per man 7 signal) is to terminate the program. Even if you did specify a handler, after it ran, you'd still be in the while(1) loop.
Here's how you'd modify your program to fix both of those problems:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
volatile sig_atomic_t got_sigalrm = 0;
void handle_sigalrm(int signum) {
got_sigalrm = 1;
}
int main() {
struct sigaction act = { .sa_handler = handle_sigalrm };
sigaction(SIGALRM, &act, NULL);
alarm(3);
printf("Hello...\n");
alarm(6);
while(!got_sigalrm);
printf("Hello2\n");
}
If I have something like this.
#include <signal.h>
#include <stdio.h>
void signalquit(int sig)
{
printf("\nQuitting..\n");
(void)signal(SIGINT, SIG_DFL);
//How to return?
}
int main(void)
{
(void)signal(SIGINT, signalquit);
while (1)
{
//Something...
}
//Continue here after quit with "Control + C"
return 0;
}
How can I return to my main function after the while loop and after quitting with Control + C? Thanks for your answers!
How to leave endless loop by signal?
By flagging that your are done.
#include <stdlib.h> /* for EXIT_XXX macros */
#include <signal.h>
volatile sig_atomic_t flag = 0;
void signalquit(int sig)
{
flag = 1;
signal(sig, SIG_DFL);
return; /* Optional for void-functions */
}
int main(void)
{
signal(SIGINT, signalquit);
while (!flag)
{
//Something...
}
return EXIT_SUCCESS;
}
Please note that not every function may be called from a signal handler. printf() for example is not guaranteed to by async-signal-safe.
To find a list of functions to be guaranteed by POSIX to be async-signal-safe scroll down here.
Your code uses the signal() function, which for historical reason is highly unportable.
A portable approach would use the function sigaction() like for example below:
#include <stdlib.h> /* for EXIT_XXX macros */
#include <stdio.h> /* for perror() */
#include <signal.h>
volatile sig_atomic_t flag = 0;
int set_sig_handler(int sig, void(*handler)(int))
{
struct sigaction sa = {0};
sa.sa_handler = handler;
return sigaction(sig, sa, NULL);
}
void signalquit(int sig)
{
flag = 1;
if (-1 == set_sig_handler(sig, SIG_DFL))
{
flag = 2;
}
}
int main(void)
{
if (-1 == set_sig_handler(SIGINT, signalquit))
{
perror("set_sig_handler() failed");
return EXIT_FAILURE;
}
while (!flag)
{
//Something...
}
if (2 == flag)
{
perror("set_sig_handler() in signal handler failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
As pointed out by pilcrow an even simpler approach is to explicitly install the handler for single use only by specifying the SA_RESETHAND flag.
#include <stdlib.h> /* for EXIT_XXX macros */
#include <stdio.h> /* for perror() */
#include <signal.h>
volatile sig_atomic_t flag = 0;
void signalquit(int sig)
{
flag = 1;
}
int main(void)
{
{
struct sigaction sa = {0};
sa.sa_handler = signalquit;
sa.sa_flags = SA_RESETHAND;
if (-1 == sigaction(SIGINT, sa, NULL))
{
perror("sigaction() failed");
return EXIT_FAILURE;
}
}
while (!flag)
{
//Something...
}
return EXIT_SUCCESS;
}
I got a strange problem that I can't solve. This is my code.
#include <stdio.h>
#include <stropts.h>
#include <signal.h>
#include <sys/types.h>
void handle_signal(int s)
{
char c = getchar();
printf("got char '%c'\n");
if(c == 'q')
{
exit(0);
}
}
int main(int argc, char** argv)
{
sigset(SIGPOLL, handle_signal);
ioctl(0, I_SETSIG, S_RDNORM);
printf("type q to exit");
while(1);
return 0;
}
When I run this program, I type character in terminal but it did not work!!! I can not receive SIGPOLL signal. Have someone can give me some advice? By the way, my operating system is ubuntu 12.04.
On Linux it needs to set O_ASYNC flag and F_SETOWN property on the file descriptor to get SIGIO signal (a synonym of SIGPOLL). And the signal handler can only call async-signal safe functions:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <ctype.h>
void handle_signal(int) { // Can only use async-signal safe functions here.
char msg[] = "got char c\n";
char* c = msg + (sizeof msg - 3);
if(1 != read(STDIN_FILENO, c, 1) || !isprint(*c))
return;
write(STDOUT_FILENO, msg, sizeof msg - 1);
if(*c == 'q')
exit(EXIT_SUCCESS);
}
int main() {
printf("type q to exit\n");
signal(SIGIO, handle_signal);
fcntl(STDIN_FILENO, F_SETFL, O_ASYNC | fcntl(STDIN_FILENO, F_GETFL));
fcntl(STDIN_FILENO, F_SETOWN, getpid());
sigset_t mask;
sigemptyset(&mask);
for(;;)
sigsuspend(&mask);
return EXIT_SUCCESS;
}
You may also like to have a look at F_SETSIG that allows receiving a signal of your choosing and extra information into the signal handler.
I am making a program containing a "Server.c" which waits a client to send it a SIGUSR1 msg 10 times, then dies, and a "client.c" which sends a SIGUSR1 msg to the server.
The problem is that if I try to access the siginfo_t* info, I get a segmentation fault.
Note that this is being tested on a Debian ssh server on which I do not have high permissions.
Node that this code works fine on Ubuntu.
Can siginfo_t *info fail due to permission issues? Or is there another issue causing this portability problem. As far as I know libc should be fairly standard throughout any linux distro, possibly unix.
Any Ideas?
Thanks
server.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int counter = 0;
pid_t *clients = 0;
void on_signal(int signo, siginfo_t *info, void * context)
{
puts("SIGNAL RECEIVED");
assert(clients);
clients[counter] = info->si_pid;
++counter;
}
int main()
{
struct sigaction action;
sigset_t set;
int recieveflag = 0;
clients = (pid_t*)malloc(10 * sizeof(pid_t));
sigemptyset(&set);
sigaddset(&set, SA_SIGINFO);
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = on_signal;
sigaction(SIGUSR1, &action, 0);
while (counter < 10) {
//sigprocmask(SIG_BLOCK, &set, 0);
sigsuspend(&set);
}
puts("I'm done!");
return 0;
}
client.c:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int main(int argc, const char** argv)
{
int server_id;
assert(argc == 2);
server_id = atoi(argv[1]);
assert(server_id > 0);
kill(server_id, SIGUSR1);
return 0;
}
I tried editing server.c to:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int counter = 0;
pid_t *clients = 0;
void on_signal(int sig)
{
puts("SIGNAL RECEIVED");
}
int main()
{
struct sigaction action;
sigset_t set;
int recieveflag = 0;
clients = (pid_t*)malloc(10 * sizeof(pid_t));
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
memset(&action, 0, sizeof(struct sigaction));
action.sa_flags = SA_SIGINFO;
action.sa_handler = on_signal;
sigaction(SIGUSR1, &action, 0);
while (counter < 10) {
sigprocmask(SIG_BLOCK, &set, 0);
sigsuspend(&set);
++counter;
}
puts("I'm done!");
return 0;
}
now it no longer receives the SIGUSR1 event at all.
The basic behavior of sigaction is to call a simple callback like : void (*sa_handler)(int);. So if you want to use the sigaction handle with 3 parameters void (*sa_sigaction)(int, siginfo_t *, void *);, you must set the sa_flags field of your struct sigaction with the flag SA_SIGINFO. Take a look of the man page : http://www.kernel.org/doc/man-pages/online/pages/man2/sigaction.2.html who is clear.