Im trying to handle SIGINT. Main purpose of SIGINT in my program cancelling current search function and printing the currently avaliable results. But whenever I try to catch a SIGINT signal it just closes my program. (I ve searched so much ,please just do not say that I have not searched enough)
I have tried :
basic signal handling(as shown as below)
sigaction functionality
non-local signal handling
sigprocmask (problem with procmask whenever I block a signal I cannot catch it but I need to catch and make printing on screen)
after all i have run out of search keyword to find a solution. Any idea ? (search keyword or part of code or logic way to do it ^^)
NOTE : This text may have grammar errors. Sorry for any mistakes.
#ifdef DEBUG
#define DPRINT(file ,message ,arg) fprintf(file ,message ,arg);
#define NDPRINT(file ,message) fprintf(file ,message);
#endif
static volatile sig_atomic_t isSignalCaught = 0;
void SIGHandler(int signo);
int main(int argc, char** argv)
{
file_t *files,*nextP;
signal(SIGINT, SIGHandler);
files = findFiles("/");
while (files != NULL) {
DPRINT(stderr, "%s\n", files->fileName.string);
nextP = files->pNext;
free(files->fileName.string);
free(files);
files = nextP;
}
return(0);
}
void SIGHandler(int signo)
{
file_t *nextP;
if (signo == SIGINT) {
isSignalCaught = 1;
}
}
Here's an example of how to do what I think you want to do.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <ctype.h>
typedef void(* sig_func_t )(int);
volatile sig_atomic_t keep_looping = 1;
void sig_handler(int sig_number) {
switch (sig_number) {
case SIGINT:
keep_looping = 0;
break;
}
}
int should_continue(void) {
char line[256];
while (1) {
printf("Continue? (y/n) ");
fgets(line, sizeof line, stdin);
if (tolower(line[0]) == 'y') {
keep_looping = 1;
signal(SIGINT, sig_handler);
return 1;
}
if (tolower(line[0]) == 'n')
break;
}
return 0;
}
int main (void) {
sig_func_t sig_func;
sig_func = signal(SIGINT, sig_handler);
if (sig_func == SIG_ERR) {
perror("signal");
exit(EXIT_FAILURE);
}
unsigned n = 0;
printf("Starting...\n");
while (1) {
while (keep_looping)
n++;
printf("Current value: n=%u\n", n);
if (!should_continue())
break;
}
signal(SIGINT, sig_func);
return EXIT_SUCCESS;
}
Related
I am writing a small shell program, while trying to handle the Ctrl+C signal, I want trying to print a newline, when it is pressed.
Here's my code to do so.
static sigjmp_buf env;
void sigint_handler(int signo){
siglongjmp(env, 42);
}
void myShellLoop(){
int parserStatus;
signal(SIGINT, sigint_handler);
while(1){
if(sigsetjmp(env,1)==42){
printf("\n");
continue;
}
//Initialize a new command, to parse and execute.
initializeGlobalCommand();
parserStatus = yyparse();
if(parserStatus == 0)
executeShellCommand();
else
printf("Not a valid shell command\n");
}
}
But after I press Ctrl+C, it does go to a newline, but then flex gives me this error:
fatal flex scanner internal error--end of buffer missed
Here's a screenshot:
How do I handle Ctrl+C properly?
Edit: Code snippet for fork():
int execute(int cmdNumber){
pid_t pid;
int status;
pid = fork();
if(pid == 0){
signal(SIGINT, SIG_DFL);
if(execvp(globalCommand.sCommands[cmdNumber].arguments[0], globalCommand.sCommands[cmdNumber].arguments) == -1){
perror("myShell: Command error");
exit(EXIT_FAILURE);
}
}
else if(pid < 0){
//Error forking.
perror("myShell");
}
else{
do{
waitpid(pid, &status, WUNTRACED);
}while(!WIFEXITED(status) && !WIFSIGNALED(status) && !globalCommand.background);
}
return 1;
}
you 'brutaly' go out of the (f)lex(/yacc/bison) code to come back in myShellLoop, so it is not surprising that introduces inconsistency
Redefine YY_INPUT and when control-c is hit return a special character to return a special value/token managed in your parser to call yyerror to abort in a normal way
For instance in your lexer file :
%{
...
extern void my_yy_input(char*, int *, int);
#undef YY_INPUT
#define YY_INPUT(b,r,s) my_yy_input(b,&r,s)
%}
...
with
static sigjmp_buf env;
void sigint_handler(int signo){
siglongjmp(env, '#');
}
void my_yy_input( char * buff, int * nRead, int maxToRead )
{
*nRead = 1;
if(sigsetjmp(env,1 ) == '#') {
*buff = '#';
return;
}
*buff = getchar();
}
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'm writing a dummy shell that should not terminate when the user types ctrl-C but should just generate a new prompt line. Currently, my shell does not terminate when I type ctrl-C but it still does not print the new prompt line. Do you know why this is the case and how I can fix this?
My code is below:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#define BUFFER_SIZE 1<<16
#define ARRAY_SIZE 1<<16
void INThandler(int);
static void parseCmdArgs(char *buffer, char** cmdArgs,
size_t cmdArgsSize, size_t *nargs)
{
char *bufCmdArgs[cmdArgsSize];
char **temp;
char *buf;
size_t n, p;
cmdArgs[0] = buf = bufCmdArgs[0] = buffer;
for(temp=bufCmdArgs; (*temp=strsep(&buf, " \n\t")) != NULL ;){
if ((*temp != '\0') && (++temp >= &bufCmdArgs[cmdArgsSize]))
break;
}
for (p=n=0; bufCmdArgs[n]!=NULL; n++){
if(strlen(bufCmdArgs[n])>0)
cmdArgs[p++]=bufCmdArgs[n];
}
*nargs=p;
cmdArgs[p]=NULL;
}
void INThandler(int sig)
{
printf("\n> ");
signal(sig, SIG_IGN);
}
int main(void)
{
char buffer[BUFFER_SIZE];
char *args[ARRAY_SIZE];
int retStatus;
size_t nargs;
pid_t pid;
printf("$dummyshell\n");
signal(SIGINT, INThandler);
while(1){
printf("> ");
fgets(buffer, BUFFER_SIZE, stdin);
parseCmdArgs(buffer, args, ARRAY_SIZE, &nargs);
if (nargs==0)
continue;
if (!strcmp(args[0], "help"))
{
printf("cat cd (absolute path references only\n");
printf("exit\n");
printf("help history\n");
printf("jobs kill\n");
printf("ls more\n");
printf("ps pwd\n");
continue;
}
if (!strcmp(args[0], "exit" ))
exit(0);
pid = fork();
if (pid){
wait(&retStatus);
}
else {
if( execvp(args[0], args)) {
fprintf(stderr, "%s\n", strerror(errno));
exit(127);
}
}
/* pid = fork();
if (pid == 0)
setpgrp();
else if (pid)
pid = wait(&retStatus);
else {
if (execvp(args[0], args)){
fprintf(stderr, "%s\n", strerror(errno));
exit(127);
}
}*/
}
return 0;
}
but what would I pass through fflush()?
It would be
fflush(stdout);
- but that is not needed because of the fgets(buffer, BUFFER_SIZE, stdin).
Output streams that refer to terminal devices are always line buffered
by default; pending output to such streams is written automatically
whenever an input stream that refers to a terminal device is read.
(See man stdio.)
I'm assuming you want the interrupt handler to jump into the while loop in your main function, instead of printing "\>".
You can use sigsetjmp and siglongjmp for this. You might want to take at [1] for an example.
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
jmp_buf JumpBuffer;
void INThandler(int);
void main(void)
{
signal(SIGINT, INThandler);
while (1) {
if (setjmp(JumpBuffer) == 0) {
printf(">");
/*...*/
}
}
}
void INThandler(int sig)
{
signal(sig, SIG_IGN);
signal(SIGINT, INThandler);
longjmp(JumpBuffer, 1);
}
This was adapted from [2]. If you use sigaction(), sigprocmask(), or sigsuspend() you need to use the siglongjmp and sigsetjmp functions, respectively [3].
Sources:
[1] https://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/apis/siglngj.htm
[2] http://www.csl.mtu.edu/cs4411.ck/www/NOTES/non-local-goto/sig-1.html
[3] sigsetjmp - The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 Edition
I'm trying to create a game in C under linux terminal.
I need to create a tetris game that consists of two c files,
One C file create execute file (a.out) and the other create (draw.out).
The first program create a child process and execute the other.
I need to send signals to the other program, but I found it difficult.
The source code is:
the first file-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <termios.h>
#include <signal.h>
char getch();
int main()
{
int fd[2],pid;
char *args[] = { "./draw.out", NULL },tav;
pipe(fd);
pid=fork();
if(pid==0)
{
execve("draw.out", args, NULL);
}
else
{
while(true)
kill(0,SIGUSR2);
}
return 1;
//getchar();
}
char getch() {
char buf = 0;
struct termios old = {0};
if (tcgetattr(0, &old) < 0)
perror("tcsetattr()");
old.c_lflag &= ~ICANON;
old.c_lflag &= ~ECHO;
old.c_cc[VMIN] = 1;
old.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSANOW, &old) < 0)
perror("tcsetattr ICANON");
if (read(0, &buf, 1) < 0)
perror ("read()");
old.c_lflag |= ICANON;
old.c_lflag |= ECHO;
if (tcsetattr(0, TCSADRAIN, &old) < 0)
perror ("tcsetattr ~ICANON");
return (buf);
}
the second file-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <signal.h>
typedef struct
{
int x;
int y;
}Point;
typedef struct
{
Point dots[3];
}Tool;
void drawBoard(int array[][20]);
void initBoard(int array[][20]);
Tool retrieveTool();
bool changeLocation(int array[][20],Tool* tool);
void my_handler(int signum);
int main()
{
bool nextTool=true;
Tool temp=retrieveTool();
int gameBoard[20][20];
signal(SIGUSR2, my_handler);
initBoard(gameBoard);
changeLocation(gameBoard,&temp);
drawBoard(gameBoard);
while(true)
{
signal(SIGUSR2, my_handler);
sleep(1);
system("clear");
if(!changeLocation(gameBoard,&temp))
temp=retrieveTool();
drawBoard(gameBoard);
}
return 1;
//getchar();
}
void initBoard(int array[][20])
{
bool isLast=false;
int i=0,j=0;
for(i=0;i<20;i++)
{
if(i==19)
isLast=true;
for(j=0;j<20;j++)
{
if((j==0)||(j==19)||(isLast))
array[i][j]=1;
else
array[i][j]=0;
}
}
}
void drawBoard(int symbols[][20])
{
int i=0,j=0;
for(i=0;i<20;i++)
{
for(j=0;j<20;j++)
if(symbols[i][j]==1)
printf("*");
else
if(symbols[i][j]==2)
printf("-");
else
printf(" ");
printf("\n");
}
}
Tool retrieveTool()
{
Tool temp;
int startX=0,startY=8,i=0;
for(i=0;i<3;i++)
{
temp.dots[i].x=startX;
temp.dots[i].y=startY;
startY++;
}
return temp;
}
bool changeLocation(int array[][20],Tool* tool)
{
int i=0;
for(i=0;i<3;i++)
{
if(array[tool->dots[i].x+1][tool->dots[i].y]!=0)
return false;
}
i=0;
for(i=0;i<3;i++)
{
array[tool->dots[i].x][tool->dots[i].y]=0;
if((tool->dots[i].x+1)==19)
tool->dots[i].x=-1;
tool->dots[i].x++;
array[tool->dots[i].x][tool->dots[i].y]=2;
}
return true;
}
void my_handler(int signum)
{
if (signum == SIGUSR2)
{
printf("Received SIGUSR1!\n");
}
}
The draw.out is the output file of the second file.
i created the signal handeler in the second file,
But the program still don't recieve the signal, what am i doing wrong?
This fragment:
while(true) kill(0,SIGUSR2);
has no sense. The kill should be used with the process id of the reveiver of SIGUSR2 (the child process in this case, identified by pid). Also note that an infinite loop sending signals to the child process is not what you want.
In the child process, you have an error in the print statement at signal handler:
printf("Received SIGUSR1!\n");
should be
printf("Received SIGUSR2!\n");
Depending on the OS version, you have to reinstall the signal handler once it gets called
Note: you are synchronizing processes, not threads
I am reading the APUE, Chapter 10. Here is my code.
#include "apue.h"
#include <unistd.h>
#include <setjmp.h>
#include <time.h>
#include <errno.h>
static void sig_usr1(int), sig_alrm(int);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjmp;
int
main(void)
{
if(signal(SIGUSR1, sig_usr1) == SIG_ERR)
err_sys("signal(SIGUSR1) error");
if(signal(SIGALRM, sig_alrm) == SIG_ERR)
err_sys("signal(SIGALRM) error");
//print signal.
pr_mask("Starting main: ");
if(sigsetjmp(jmpbuf, 1)) {
pr_mask("End main: ");
exit(0);
}
canjmp = 1;
for(;;)
pause();
}
static void
sig_usr1(int signo)
{
time_t starttime;
if(canjmp == 0) {
return;
}
pr_mask("starting sig_usr1: ");
alarm(3);
starttime = time(NULL);
for(;;)
if(time(NULL) > starttime + 5)
break;
pr_mask("finishing sig_usr1: ");
canjmp = 0;
siglongjmp(jmpbuf, 1);
}
static void
sig_alrm(int signo)
{
pr_mask("in sig_arlm: ");
}
void
pr_mask(const char *str)
{
sigset_t sigset;
int errno_save;
errno_save = errno; /* we can be called by signal handlers */
if (sigprocmask(0, NULL, &sigset) < 0)
err_sys("sigprocmask error");
printf("%s", str);
if (sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 ");
if (sigismember(&sigset, SIGALRM)) printf("SIGALRM ");
/* remaining signals can go here */
printf("\n");
errno = errno_save;
}
I thought the output would be like this:
Starting main:
starting sig_usr1: SIGUSR1
in sig_alrm: SIGUSR1 SIGALRM
finishing sig_usr1: SIGUSR1
End main:
but it seems something wrong, this is my output in fact:
Starting main:
starting sig_usr1:
in sig_alrm:
finishing sig_usr1:
End main:
that is no signals. Please help me.
I think the trouble is probably that you are using signal() and not sigaction() to set the signal handling. And signal() does not mask any other signals - so there are no signals to show as being blocked. I modified your code as shown below, to use signal() and sigaction() depending on whether there are any arguments or not.
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef void (*Handler)(int);
static void sig_usr1(int), sig_alrm(int);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjmp;
static void pr_mask(const char *str);
static void err_sys(const char *str)
{
int errnum = errno;
fprintf(stderr, "%s (%d: %s)\n", str, errnum, strerror(errnum));
exit(1);
}
static void set_sigaction(int signum, Handler handler)
{
struct sigaction nact;
nact.sa_handler = handler;
sigfillset(&nact.sa_mask);
//sigemptyset(&nact.sa_mask);
nact.sa_flags = 0;
if (sigaction(signum, &nact, 0) != 0)
err_sys("Failed to set signal handling");
}
int
main(int argc, char **argv)
{
printf("PID = %u\n", (unsigned)getpid());
if (argc > 1)
{
if (signal(SIGUSR1, sig_usr1) == SIG_ERR)
err_sys("signal(SIGUSR1) error");
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
err_sys("signal(SIGALRM) error");
}
else
{
set_sigaction(SIGUSR1, sig_usr1);
set_sigaction(SIGALRM, sig_alrm);
}
//print signal.
pr_mask("Starting main: ");
if (sigsetjmp(jmpbuf, 1)) {
pr_mask("End main: ");
exit(0);
}
canjmp = 1;
for (;;)
pause();
}
static void
sig_usr1(int signo)
{
time_t starttime;
if (canjmp == 0) {
return;
}
pr_mask("starting sig_usr1: ");
alarm(3);
starttime = time(NULL);
for (;;)
if (time(NULL) > starttime + 5)
break;
pr_mask("finishing sig_usr1: ");
canjmp = 0;
siglongjmp(jmpbuf, 1);
}
static void
sig_alrm(int signo)
{
pr_mask("in sig_arlm: ");
}
void
pr_mask(const char *str)
{
sigset_t sigset;
int errno_save;
errno_save = errno; /* we can be called by signal handlers */
if (sigprocmask(0, NULL, &sigset) < 0)
err_sys("sigprocmask error");
printf("%s", str);
if (sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 ");
if (sigismember(&sigset, SIGALRM)) printf("SIGALRM ");
/* remaining signals can go here */
printf("\n");
errno = errno_save;
}
Running on MacOS X 10.7.2 with current XCode (4.2?), I get (for example):
$ ./sigtest
PID = 11066
Starting main:
starting sig_usr1: SIGUSR1 SIGALRM
finishing sig_usr1: SIGUSR1 SIGALRM
in sig_arlm: SIGUSR1 SIGALRM
End main:
$ ./sigtest 1
PID = 11067
Starting main:
starting sig_usr1: SIGUSR1
in sig_arlm: SIGUSR1 SIGALRM
finishing sig_usr1: SIGUSR1
End main:
$