Thread: How to stop reading from keyboard once a signal is handled?

  1. #1
    Registered User
    Join Date
    Sep 2016
    Posts
    12

    Question How to stop reading from keyboard once a signal is handled?

    I'm writing a program where the SIGINT signal is handled the first time it is sent, but set to default after that. So, for example, I have this:

    Code:
    static volatile int stop_terminating = 1;
    
    void handler(int dummy) {
        stop_terminating = 0;
    }
    
    int main(){
        signal(SIGINT, handler);
        char input[256];
        while(1){
            if(stop_terminating == 0){
                // reset the action of the signal to default
                signal(SIGINT, SIG_DFL);
                printf("Message sent.\n");
                // increment counter so it doesn't enter this condition again
                stop_terminating++;
            }
            printf("User input:\n");
            fgets(input, sizeof(input), stdin);
            // In this stage, I wanna press CTRL+C and print a message, stopping the fgets
            // but what happens is: I press CTRL+C, the signal is catched, but fgets
            // is still asking for an input, and after I send something, the my message is printed
            // because it looped through the while(1) again.
        }
    }
    How can I stop fgets from asking for an input and just print the message and then ask again for an input?

  2. #2
    Registered User
    Join Date
    Sep 2016
    Posts
    12
    I solved it using sigaction()

    signal(2, handler);
    sigaction(2, 1);

    does the trick.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Perhaps you could post your latest code, because your call to sigaction() looks like junk.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Sep 2016
    Posts
    12
    Lol, I'm sure it is, but it works so far. I don't know how to resume my code, it's pretty long for just making a point about signals, but here it goes... a short and probably flawed version:

    Code:
    int main(int argc, char *argv[]){
        // signal 2 is SIGINT
        siginterrupt(2, 1);
        // use handler to handle SIGINT. This will just raise a flag
        // to detect the first time CTRL+C is pressed. FLAG = 0 initially
        signal(2, handler);
        
        pid_t children[NUM_CHILDREN];
        pid_t parent = getpid();
        create_children(parent, children, NUM_CHILDREN);
        // this is just a function that asks the user to enter a child and signal to send
        // it also resets the flag!
        ask_for_signal(parent, children, NUM_CHILDREN);
        return 0;
    }
    
    
    void create_children(pid_t parent, pid_t *children, int NUM_CHILDREN){
        int i;
        for(i = 0; i < NUM_CHILDREN; i++){
            children[i] = fork();
            if(pid[i] < 0){
                perror("Error en el fork.");
                exit(1);
            // create children from the same parent
            } else if(children[i] == 0 && getppid() == parent) {
                if(menu == 1){
                    printf("Number: %d   ,pid: %d\n", i+1, getpid());
                }
                wait_signal();
            }
        }
    }
    
    
    void wait_signal() {
        sigset_t sigset;
        sigemptyset(&sigset);
        sigaddset(&sigset, 16);
        sigaddset(&sigset, 17);
        sigprocmask(SIG_SETMASK, &sigset, NULL);
     
        int counter = 0;
        int result;
        while(1){
            if(handler_flag == 1){
                // the user has pressed ctrl+c
                // return SIGINT back to normal so it can terminate the children
                signal(2, SIG_DFL);
            }
            if ((result = sigwaitinfo(&sigset, NULL)) > 0){
                if(result == 16){
                    printf("<pid: %d, y he recibido esta llamada %d veces>\n", getpid(), ++counter);
                } else if(result == 17){
                    fork();
                }
            }
        }
    }
    Last edited by sebasura; 04-06-2017 at 08:52 AM.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Well see, there's my point.
    > // signal 2 is SIGINT
    > siginterrupt(2, 1);
    Why don't you just use the symbolic name directly in the call.

    The same goes for all the other magic numbers like 16 and 17 (which would seem to be SIGUSR1 and SIGUSR2 respectively).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Your original question in this thread is indecipherable. I have no idea what you are asking there.

    Anyway, you should post your entire program (including the includes!) so we can take a good look at it.

    I don't see you using sigaction anywhere, so I don't know what that's all about.

    And as Salem said, switching from using SIGINT, etc, to a bunch of arbitrary numbers is loony!

  7. #7
    Registered User
    Join Date
    Sep 2016
    Posts
    12
    This is for an assignment and they gave us a table with signal names and numbers. The table says SIGINT: 2, SIGUSR1: 16, SIGUSR2: 17.
    The user should enter those values in console like this: Child_num - Signal_num (e.g. 1 - 15, 2-16, 3 -17, etc)
    If I use SIGUSR1 and SIGUSR2 instead of 16 and 17, the program doesn't work. Reading the signal's manual page, it says:
    SIGUSR1 30,10,16 Term User-defined signal 1
    SIGUSR2 31,12,17 Term User-defined signal 2

    I'm assuming the OS may be using 30 and 31, or maybe it's interchangeable, I don't know, but the user must use 16 and 17 in console, so I made things simpler. They are not arbitrary numbers, but I don't know if that's "legal" though.
    The due date for this is tomorrow at 23:55hrs, I'm afraid my code may be sniped and my teacher thinks I copied or something.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Why are you worried about copying (unless you actually copied it).
    If seeking online help is within your assignment guidelines, you can prove you're the original author simply by logging in in front of your tutor.

    > I don't know, but the user must use 16 and 17 in console
    This seems like a poor question where the question writer blindly assumed particular values.

    The 'kill' command supports symbolic names anyway, so there really is no need to actually assume any value at all.
    Eg.
    $ kill -USR1 3000
    $ kill -USR2 3001


    Randomly hijacking 16 and 17 when they're not the USR[12] signals on your system seems like a recipe for disaster, if your system actually uses those for something else entirely.

    Even if you're forced to use signals 16 and 17, you can still greatly improve readability by doing
    #define MYSIG1 16
    #define MYSIG2 17
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Sep 2014
    Posts
    364
    Quote Originally Posted by sebasura View Post
    This is for an assignment and they gave us a table with signal names and numbers. The table says SIGINT: 2, SIGUSR1: 16, SIGUSR2: 17.
    The user should enter those values in console like this: Child_num - Signal_num (e.g. 1 - 15, 2-16, 3 -17, etc)
    If I use SIGUSR1 and SIGUSR2 instead of 16 and 17, the program doesn't work. Reading the signal's manual page, it says:
    SIGUSR1 30,10,16 Term User-defined signal 1
    SIGUSR2 31,12,17 Term User-defined signal 2

    I'm assuming the OS may be using 30 and 31, or maybe it's interchangeable, I don't know, but the user must use 16 and 17 in console, so I made things simpler. They are not arbitrary numbers, but I don't know if that's "legal" though.
    The due date for this is tomorrow at 23:55hrs, I'm afraid my code may be sniped and my teacher thinks I copied or something.
    The numbers are for different architectures.
    This is a part from the manualpage of signal (man 7 signal):
    Code:
       Standard signals
           Linux  supports  the  standard  signals  listed  below.   Several signal numbers are architecture-dependent, as indicated in the
           "Value" column.  (Where three values are given, the first one is usually valid for alpha and sparc, the middle one for x86, arm,
           and most other architectures, and the last one for mips.  (Values for parisc are not shown; see the Linux kernel source for sig-
           nal numbering on that architecture.)  A - denotes that a signal is absent on the corresponding architecture.)
    
    
           First the signals described in the original POSIX.1-1990 standard.
    
    
           Signal     Value     Action   Comment
           ----------------------------------------------------------------------
           SIGHUP        1       Term    Hangup detected on controlling terminal
                                         or death of controlling process
           SIGINT        2       Term    Interrupt from keyboard
           SIGQUIT       3       Core    Quit from keyboard
           SIGILL        4       Core    Illegal Instruction
           SIGABRT       6       Core    Abort signal from abort(3)
           SIGFPE        8       Core    Floating point exception
           SIGKILL       9       Term    Kill signal
           SIGSEGV      11       Core    Invalid memory reference
           SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                         readers
           SIGALRM      14       Term    Timer signal from alarm(2)
           SIGTERM      15       Term    Termination signal
           SIGUSR1   30,10,16    Term    User-defined signal 1
           SIGUSR2   31,12,17    Term    User-defined signal 2
           SIGCHLD   20,17,18    Ign     Child stopped or terminated
           SIGCONT   19,18,25    Cont    Continue if stopped
           SIGSTOP   17,19,23    Stop    Stop process
           SIGTSTP   18,20,24    Stop    Stop typed at terminal
           SIGTTIN   21,21,26    Stop    Terminal input for background process
           SIGTTOU   22,22,27    Stop    Terminal output for background process
           The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
    
    
           Next the signals not in the POSIX.1-1990 standard but described in SUSv2 and POSIX.1-2001.
    
    
           Signal       Value     Action   Comment
           --------------------------------------------------------------------
           SIGBUS      10,7,10     Core    Bus error (bad memory access)
           SIGPOLL                 Term    Pollable event (Sys V).
                                           Synonym for SIGIO
           SIGPROF     27,27,29    Term    Profiling timer expired
           SIGSYS      12,31,12    Core    Bad argument to routine (SVr4)
           SIGTRAP        5        Core    Trace/breakpoint trap
           SIGURG      16,23,21    Ign     Urgent condition on socket (4.2BSD)
           SIGVTALRM   26,26,28    Term    Virtual alarm clock (4.2BSD)
           SIGXCPU     24,24,30    Core    CPU time limit exceeded (4.2BSD)
           SIGXFSZ     25,25,31    Core    File size limit exceeded (4.2BSD)
    
    
           Up to and including Linux 2.2, the default behavior for SIGSYS, SIGXCPU, SIGXFSZ, and (on architectures  other  than  SPARC  and
           MIPS) SIGBUS was to terminate the process (without a core dump).  (On some other UNIX systems the default action for SIGXCPU and
           SIGXFSZ is to terminate the process without a core dump.)  Linux 2.4 conforms to the POSIX.1-2001 requirements  for  these  sig-
           nals, terminating the process with a core dump.
    
    
           Next various other signals.
    
    
           Signal       Value     Action   Comment
           --------------------------------------------------------------------
           SIGIOT         6        Core    IOT trap. A synonym for SIGABRT
           SIGEMT       7,-,7      Term
           SIGSTKFLT    -,16,-     Term    Stack fault on coprocessor (unused)
           SIGIO       23,29,22    Term    I/O now possible (4.2BSD)
           SIGCLD       -,-,18     Ign     A synonym for SIGCHLD
           SIGPWR      29,30,19    Term    Power failure (System V)
           SIGINFO      29,-,-             A synonym for SIGPWR
           SIGLOST      -,-,-      Term    File lock lost (unused)
           SIGWINCH    28,28,20    Ign     Window resize signal (4.3BSD, Sun)
           SIGUNUSED    -,31,-     Core    Synonymous with SIGSYS
    
    
           (Signal 29 is SIGINFO / SIGPWR on an alpha but SIGLOST on a sparc.)
    
    
           SIGEMT  is not specified in POSIX.1-2001, but nevertheless appears on most other UNIX systems, where its default action is typi-
           cally to terminate the process with a core dump.
    
    
           SIGPWR (which is not specified in POSIX.1-2001) is typically ignored by default on those other UNIX systems where it appears.
    
    
           SIGIO (which is not specified in POSIX.1-2001) is ignored by default on several other UNIX systems.
    
    
           Where defined, SIGUNUSED is synonymous with SIGSYS on most architectures.
    As you can see, using the named macros is important here.
    If you compile your code on another architecture, you will end up in a desaster.
    Other have classes, we are class

  10. #10
    Registered User
    Join Date
    Sep 2016
    Posts
    12
    I get your point and I totally agree. The thing is... when I send the signal 16 and 17, the program doesn't work.
    Those are the values that my blind problem writer told me to use, so I'm kind of in a problem here. I would have to change the program by making the users input the signal name, and not the number, but that's not what the problem asks for.

  11. #11
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    I'm curious about your program. It looks interesting. Could you PM me a copy?

  12. #12
    Registered User
    Join Date
    Sep 2016
    Posts
    12
    Quote Originally Posted by algorism View Post
    I'm curious about your program. It looks interesting. Could you PM me a copy?
    GitHub - sebasura/sistope

  13. #13
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Very good job. A few points.

    Technically, handler_flag should be of type sig_atomic_t:
    static volatile sig_atomic_t handler_flag = 0;

    Instead of initializing num_hijos and menu in main, initialize them first thing in catch_getopt.

    In catch_getopt, you don't need to cast *num_hijos to int (it's already an int). And instead of just testing if it's 0, you should check if it's <= 0 since the user could enter a negative number.

    parsear should return a boolean (int with value 0 or 1), not an int*. That would express the point of the return value more clearly. (Especially if you included stdbool.h and used a bool with true and false.)

    You should put an exit(0) after the esperar_signal(i) call to ensure that no child continues past that point. (I realize that esperar_signal has an infinte loop, but it's still good practice and allows the reader of the code to see right away that the child will not continue after that point.)

    In crear_hijos you "verify that the children come from the same parent" but I don't see how it could be otherwise. That check is not needed.

    Likewise in pedir_signal, I don't see how any process but the original parent could possibly be running that code (especially if you add the exit that I mentioned before).

    Your comment says you are "increasing" the flag when you are actually decremeting it:
    handler_flag--;
    Simply setting it to 0 would be clearer (it's essentially boolean). Also, when we test boolean values, we don't usually say if (handler_flag == 1). Instead we just say if (handler_flag)

    In parsear, you shouldn't use a loop to strtok the values. What if the user entered 3 or more values? Your code would keep reading them into successive positions of input (which only has 2 positions allocated). Actually, strtok is not really appropriate here. I would just use sscanf
    sscanf(entrada, "%d - %d", input, input+1);

    In esperar_signal, you don't use the parameter n. Maybe you want to print it out along with the pid ("I am child 3 (pid 1234) ...").

    To get gcc (or c99) to tell you about unused variables AND unused parameters, you need to give both the -Wall flag and the -W flag (which is also called -Wextra).

    I don't understand what the fork() in esperar_signal is supposed to do. That child (of a child) will be alone in the wilderness and will not be able to be communicated with by the original parent (or even the child that created it). It just waits for a signal that will never come.

  14. #14
    Registered User
    Join Date
    Sep 2016
    Posts
    12
    Thanks for the corrections . About the unused values, comment saying increase and stuff like that, It's because I fixed some errors and I changed the logic in a few ways, and the comment stayed as before. The unused n value was a fix too. The atomic value I didn't know how to declare it, thank you. I will try to improve the code by following your advice.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 44
    Last Post: 04-02-2016, 07:14 AM
  2. How to stop reading input...
    By intull in forum C Programming
    Replies: 8
    Last Post: 02-20-2011, 03:38 AM
  3. reading wifi signal level with C
    By occam25 in forum Linux Programming
    Replies: 2
    Last Post: 07-19-2010, 03:12 PM
  4. reading wifi signal level with C
    By occam25 in forum Networking/Device Communication
    Replies: 4
    Last Post: 07-19-2010, 04:58 AM
  5. keyboard stop working at Dos
    By arian in forum C++ Programming
    Replies: 1
    Last Post: 11-18-2004, 02:32 PM

Tags for this Thread