cposixsigaction

client - server program for transmitting text using signals SIGUSR1, SIGUSR2


server

typedef struct s_server
{
    unsigned char c;
    int counter;
}               t_server;

t_server server;

void    ft_one(int sig, siginfo_t *info, void *context)
{
    (void)sig;
    (void)context;
    server.c += server.counter;
    server.counter /= 2;
    if (server.counter == 0)
    {
        write(1, &server.c, 1);
        server.c = 0;
        server.counter = 128;
    }
    kill(info->si_pid, SIGUSR1);
}

void    ft_zero(int sig, siginfo_t *info, void *context)
{
    (void)sig;
    (void)context;
    server.counter /= 2;
    if (server.counter == 0)
    {
        write(1, &server.c, 1);
        server.c = 0;
        server.counter = 128;
    }
    kill(info->si_pid, SIGUSR1);
}

int main(void)
{
    struct sigaction act_one;
    struct sigaction act_zero;

    memset(&act_one, '\0', sizeof(act_one));
    memset(&act_zero, '\0', sizeof(act_zero));
    act_one.__sigaction_u.__sa_sigaction = ft_one;
    act_zero.__sigaction_u.__sa_sigaction = ft_zero;
    act_one.sa_flags = SA_SIGINFO;
    act_zero.sa_flags = SA_SIGINFO;
    if (sigaction(SIGUSR1, &act_one, NULL) < 0)
        return (0);
    if (sigaction(SIGUSR2, &act_zero, NULL) < 0)
        return (0);
    printf("server pid: %d\n", getpid());
    server.c = 0;
    server.counter = 128;
    while (1)
        pause();
    return (0);
}

client

void empty(int sig, siginfo_t *info, void *context)
{
    (void)sig;
    (void)context;
    (void)info;
}

int main(int argc, char **argv)
{
    int i;
    struct sigaction act;
    char *str;
    int serv_pid;

    memset(&act, '\0', sizeof(act));
    act.__sigaction_u.__sa_sigaction = empty;
    act.sa_flags = SA_SIGINFO;
    serv_pid = atoi(argv[1]);
    str = argv[2];
    if (sigaction(SIGUSR1, &act, NULL) < 0)
        return (0);
    while (*str)
    {
        i = 128;
        while (i > 0)
        {
            if (i & (unsigned char)*str)
            {
                if (kill(serv_pid, SIGUSR1) == -1)
                    return (0);
            }
            else
            {
                if (kill(serv_pid, SIGUSR2) == -1)
                    return (0);
            }
            i /= 2;
            pause();
        }
        str++;
    }
    return (0);
}

The screenshots show the result of work, programs. In the first case, I call the client several times. In the second with a lot of text. In both cases, apparently, the response signal from the server does not go away. Why? I can t understand enter image description here. enter image description here


Solution

  • You have a race condition in the client program. There is no guarantee that the signal will be delivered after the client calls pause.

    The correct way is to use sigprocmask and sigsuspend. Block incoming SIGUSR1 with sigprocmask. After sending the bit, instead of calling pause, call sigsuspend with a mask that unblocks SIGUSR1. sigsuspend will return when the signal is caught, and block again.

    sigset_t myset, oldset;
    sigemptyset(&myset);
    sigaddset (&myset, SIGUSR1);
    sigprocmask(SIG_BLOCK, &myset, &oldset);
    
    while (*str)
    {
      ...
      // pause() -- wrong! race condition!
      sigsuspend(&oldset);
      ...
    }