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
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);
...
}