0

I have a problems to communicate a signal from parent process to child, cause its like the child didnt open correctly cause when i do if(oct_pid == 0) i cant enter in.

calculator.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <sys/file.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>


void octal(int fd){
    int valor;
    while (1)
    {
        pause();
        read(fd,&valor,sizeof(int));
        printf("%o",valor);
    }
}

void hexa(int fd){
    int valor;
    while (1)
    {
        pause();
        read(fd,&valor,sizeof(int));
        printf("%X",valor);
    }
}


int main(){
    int canal,pipe_fd[2],octal_pid,hexa_pid;

    unlink("canal");

    if(mkfifo("./canal", 00660)!=0){
        printf("Error al crear la pipe");
        exit(EXIT_FAILURE);
    }

    canal = open("./canal",O_RDONLY);
    if(canal < 0){
        printf("Error al obrir la pipe.");
        exit(EXIT_FAILURE);
    }
    
    pipe(pipe_fd);

    octal_pid = fork();

    if(octal_pid == -1){
        printf("Error al crear el proceso octal.\n");
        exit(EXIT_FAILURE);
    } else if(octal_pid == 0){
        close(pipe_fd[1]);
        octal(pipe_fd[0]);
        signal(SIGUSR1,octal);
    } else {
        hexa_pid = fork();
        if(hexa_pid == -1){
            printf("Error al crear el proceso hexadecimal.\n");
            kill(octal_pid, SIGTERM);
            exit(EXIT_FAILURE);
        } else if(hexa_pid == 0){
            close(pipe_fd[1]);
            hexa(pipe_fd[0]);
            signal(SIGUSR1,hexa);
        } else {
            close(pipe_fd[0]);
            while(1){
                char c;
                int valor;
                read(canal,&c,sizeof(char));
                read(canal,&valor,sizeof(int));
                if(c == 'o'){
                    printf("Calculant en octal ... \n");
                    write(pipe_fd[1], &valor, sizeof(int));
                    kill(octal_pid,SIGUSR1);
                }
                else if(c == 'h'){
                    printf("Calculant en hexadecimal ... \n");
                    write(pipe_fd[1], &valor, sizeof(int));
                    kill(hexa_pid,SIGUSR1);
                }
                else if( c == 'x'){
                    printf("Sortint...\n");
                    kill(octal_pid, SIGTERM);
                    kill(hexa_pid, SIGTERM);
                    break;
                }   
            }
            close(canal);
            close(pipe_fd[1]);
            waitpid(octal_pid, NULL, 0);
            waitpid(hexa_pid, NULL, 0);
        }
    }
    return 0;
}

client.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <sys/file.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>

int fd, valor;
char operacio;

int llegir_numero()
{
    char buff [10]; 
    int llegits;
    llegits=read(0, buff, 10); //llegir del teclat un màxim de 10 chars
    buff[llegits-1] = (char)0; //canvi del \n per un \0
    return(atoi(buff)); //es converteix a enter
}

int main(){

    fd = open("./canal",O_WRONLY);

    if(fd < 0){
        printf("La pipe no s'ha obert correctament.");
        exit(EXIT_FAILURE);
    }

    do{
        printf("Introdueix 'o' o 'h', x per acabar\n");
        scanf(" %c",&operacio);

        if(operacio == 'o' || operacio == 'h'){
            printf("Introdueix un valor enter positiu:\n");
            valor = llegir_numero();
            write(fd,&operacio,sizeof(char));
            write(fd,&valor,sizeof(int));
        }
        else if(operacio != 'x'){
            printf("Lletra incorrecte.");
        }
    }
    while(operacio != 'x');
    close(fd);
    return 0;
}

I have this code where I have a problem with kill(octal_pid,SIGUSR1), when, in theory, I send the signal to the child process octal_pid, it didnt work cause I cant enter in this pipe and idk why. Thanks for the help

  • 1
    Why are you using `signal` at all? You're already using pipes. Better [for the parent] to read to EOF on the pipe. A child issues a signal _after_ writing to the pipe and closing it. But, the signal may show up in the parent _before_ it has read any data. This is a _race condition_. Change the `signal` calls in the child(ren) to (e.g.) `exit(0);` (i.e.) Don't use `signal` for this use case. – Craig Estey May 09 '23 at 19:12
  • @CraigEstey I suspect this is a coding exercise of some type, where the use of signals is part of the problem. – Andrew Henle May 09 '23 at 19:50
  • @AndrewHenle We need to see the body of the signal handler to help further. But, an error: In the child, `signal(SIGUSR1,hexa);` establishes a child handler for `SIGUSR1` as `hexa` which is a variable. This should be: `kill(getppid(),SIGUSR1);`. I agree: use `sigaction` and _not_ `signal`. But, we have to use [queued] RT signals. For: `child1: kill SIGUSR1 | child2: kill SIGUSR1 | parent: handler()`, the parent will receive only _one_ signal. `sigaction` won't help this because there is just a sigpending _mask_ [in the kernel task struct] for the process for ordinary [non-RT] signals. – Craig Estey May 09 '23 at 20:13
  • ye thats an excercice where i have 2 programs this and one name client.c where i read the option that i want to use (o/h) and the number, and I send it to the named_pipe that I create in calculator.c(code above), I think that the problem is that when i do the kill() I never enter in the child cause I dont open it correlecty. – loststudent May 09 '23 at 21:35
  • We want an [MRE](https://stackoverflow.com/help/minimal-reproducible-example). For C, we want a _single_ `.c` file [_with_ (e.g.) `#include `]. But, _no_ (e.g.) `#include "myprogram.h"`. For runtime errors, it should compile cleanly. We should be able to download it and build and run it on our local systems [if we so choose]. In your case, we need `calculator.c` _and_ `client.c` in _separate_ code blocks. Currently, AFAICT, the solution is in the code that you're _not_ showing. And, how about a block quote with the problem description? – Craig Estey May 09 '23 at 22:07
  • like this?, I'm new at this sorry :D @CraigEstey – loststudent May 09 '23 at 22:36
  • Yes, thank you. But, your `void handler(int signal){}` has an empty body (i.e. no code). So, what do you want the parent to do when it gets a signal? And, it would help to post the assignment description. This would tell us what the intent is. Without it, we have to look at the code (i.e. your implementation) to try to guess at the intent. (e.g.) Is the use of signals _required_ by the assignment? Or, is this just part of _your_ solution? – Craig Estey May 09 '23 at 22:44
  • The use of signals is required. The assigment is to use client.c to read the values (option and the number that you want to convert) and sent to the named pipe that i create in calculator.c, and calculator.c needs to create the named_pipe and make two process, one from the octal_convert and the other frm hexa_convert. These are the child process, and the parent process will read the option from named_pipe and send the signal to the appropriate process. The output its something like: Option: c Number: 8 Convert to octal... The number is 0o10 and ask again the letter – loststudent May 09 '23 at 22:56
  • @CraigEstey The signal handlers **are** provided. For example, `void octal(int fd)` is the signal handler set by `signal(SIGUSR1,octal);` Of course, `octal(int fd )` **won't work** as a signal handler as currently coded. – Andrew Henle May 09 '23 at 23:29

2 Answers2

2

Besides the problems Andrew Henle notes, your two children that you fork will exit immediately after registering a signal handler. Timing is uncertain, but it is likely that they'll be dead by the time the signal is sent to them, so the signal will do nothing.

Aside from that, the signal handler will call pause and wait for a second signal before actually doing anything.

To avoid these problems, you should have the while (1) pause(); loop in main for the children after calling signal, and should have neither a loop nor a pause call in the signal handlers.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
1

First, read this:

What is the difference between sigaction and signal?

You really need to use sigaction() on POSIX systems instead of signal().

Second, given

void octal(int fd){
    int valor;
    while (1)
    {
        pause();
        read(fd,&valor,sizeof(int));
        printf("%o",valor);
    }
}

this is wrong:

    signal(SIGUSR1,octal);

because the int argument that gets passed to a signal handler is the value if the signal - not some file descriptor. You need to find another way to pass the proper file descriptor values to your signal handler.

Also, you need to install the signal handler (using sigaction()) before you call fork(), or your child process could very well send signals and even complete running before the parent process gets its signal handler(s) installed.

Finally, multiple signals of the same type can be coalesced into one signal, so if your child process sends, for example, 8 SIGUSR1 signals, the parent process might only get one of them. Note also this question and answer: Blocking signals in C

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • I need to use siganls to activate the functions, SIGUSR1 to activate and SIGUSR2 to desactivate it, I think that the problem is cause I cant enter in the pipe where I send the signal with kill(), but idk why – loststudent May 09 '23 at 21:36
  • @loststudent Nothing in this answer contradicts that... – Andrew Henle May 09 '23 at 23:29