Returning from Signal Handlers
Asked Answered
F

2

5

Am I not leaving my signal handler function in the correct way? It does not seem to return to the program normally. Instead it goes into the loop and where it should wait for user input, it skips and reads the length of the "user input" to -1 and errors out. (Will make more sense in code.)

void handle_SIGINT() {

    int k = recent;
    int count = 0;
    int stop;

    if (stringSize >= 10) {
        stop = 10;
    }
    else {
        stop = p;
    }

    printf("\nCommand History:\n");

    for (count = 0; count < stop; count++) {

        if (k < 0) {
            k += 10;
        }
        printf("%s", string[abs(k)]);
        k -= 1;

    }

}



void setup(char inputBuffer[], char *args[],int *background)
{
    //char inputBuffer[MAX_LINE];
    int length, /* # of characters in the command line */
    i,      /* loop index for accessing inputBuffer array */
    start,  /* index where beginning of next command parameter is */
    ct;     /* index of where to place the next parameter into args[] */
    int add = 1;
    ct = 0;

    /* read what the user enters on the command line */
    length = read(STDIN_FILENO, inputBuffer, MAX_LINE);  


        printf("%i",length);
    start = -1;
    if (length == 0)
        exit(0);            /* ^d was entered, end of user command stream */
    if (length < 0){
        perror("error reading the commanddddddddd");
        exit(-1);           /* terminate with error code of -1 */
    }
}



int main(void)
{
    char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
    int background;             /* equals 1 if a command is followed by '&' */
    char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */
    FILE *inFile = fopen("pateljay.history", "r");



    if (inFile != NULL) {
        int count = 0;
        char line[MAX_LINE];
        while (fgets(line,sizeof line, inFile) != NULL) {
            string[count] = strdup(line);
            //string[count][strlen(line)] = '\n';
            //string[count][strlen(line) + 1] = '\0';
            printf("%s", string[count]);
            count++;
            stringSize++;
        }


            p = count % 10;
            recent = abs(p - 1);

    }   

    fclose(inFile); 

    /* set up the signal handler */
    struct sigaction handler;
    handler.sa_handler = handle_SIGINT;
    sigaction(SIGINT, &handler, NULL);

    while (1) {/* Program terminates normally inside setup */


        background = 0;
        printf("COMMAND->");

        fflush(0);

        setup(inputBuffer, args, &background);/* get next command */
    }
}

So when ctrl+c is entered it should catch the signal and handle it. Once it returns back to main, it goes into setup and completely skips the read function and makes length equal to -1. This in turn errors out the program. I think the code inside handle_SIGINT is irrelevant as it is right now. Does anyone know any reason why it would be skipping the read function in setup?

Finnic answered 29/11, 2011 at 0:15 Comment(12)
You cannot use printf() in a signal handler.Sciuroid
It seemed to work when I ran it, however I think you are right. I just did not know what to use in its stead because I am not that familiar with C.Finnic
@wildplasser: Why can one not use printf in a signal handler?Toucan
The system man pages will usually have a list of which functions are safe to call from signal handlers (on my system, it's in the page for sigaction(2)). In particular, it lists write(2) as safe to call, which you could use here.Lawlor
@Sciuroid I think that he can. If you see the example at the man page of the mprotect it has a printf()Mckenna
BTW where is "string" defined?Sciuroid
it is globally defined. char *string[SAVED_BUFFER]; int p = 0; int recent = -1; int stringSize = 0; and I am trying to look into which functions can be called in a signal handlerFinnic
About the printf issue, when used inside a signal handler, see this question and answer: #2462083Hydroquinone
@Tom: because it is not re-entrant. (printf might call malloc to get bufferspace, and since it is invoked from a signalhandler, that might disrupt malloc. Maybe stdio's housekeeping might get confused too, when interrupted)Sciuroid
@Sciuroid Ok now it is clear. Nice info!Mckenna
Getting printf out of your signal handler is a pretty tricky problem. See osiris.978.org/~alex/safesignalhandling.html for some solutions.Galimatias
should I be only changing the state of a boolean in the signal handler and using printf outside in main? Would that be better?Finnic
G
8

read is blocking, waiting for input. SIGINT arrives. The kernel calls your signal handler. When your signal handler returns, the kernel makes read return -1 and set errno to EINTR. You need to check for this case and handle it by calling read again:

   do {
        length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
   } while (length == -1 && errno == EINTR);
Galimatias answered 29/11, 2011 at 0:34 Comment(6)
errno is defined by kernel for all programs?Finnic
By the way, I'd never use this solution except in a toy program, because it doesn't fix the problem of calling printf from a signal handler, which is forbidden. In a serious program I'd use the self-pipe trick.Galimatias
You need to #include <errno.h> to get the correct definition of errno.Galimatias
Okay thanks a lot, especially for the extra information on signal handlers. I looked up the self-pipe trick and might give it a try. Also found some information on pselect. Not sure what select actually does, am I supposed to include it in my while loop to make the signal handler return there?Finnic
I would recommend poll instead of select, because poll's interface is simpler. For either, this page might be useful: publib.boulder.ibm.com/infocenter/iseries/v6r1m0/…Galimatias
@Finnic it is defined in libcSprings
S
1

The signal handler is supposed to take an int argument:

void handle_sigint(int signum) {}
Sciuroid answered 29/11, 2011 at 0:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.