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

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

Related

zsh: user-defined signal 1

client :
char *content = NULL;
void send_to_server_bonus(int pid, char *string)
{
size_t lenstring;
int j;
size_t i;
i = 0;
lenstring = ft_strlen_bonus(string);
while (i <= lenstring)
{
j = 0;
while (j < 8)
{
if (((string[i] >> j) & 1) == 1)
kill(pid, SIGUSR1);
else
kill(pid, SIGUSR2);
j++;
usleep(1000);
}
i++;
}
//ft_putstr(content);
}
#include <stdio.h>
void sig1handler(int sum)
{
sum = 0;
content = "adfa";
printf("The message is received\n");
fflush(NULL);
}
int main(int argc, char **argv)
{
if (argc == 3)
{
send_to_server_bonus(ft_atoi_bonus(argv[1]), argv[2]);
signal(SIGUSR1, sig1handler);
}
return (0);
}
server :
int signalPid = 0;
void sighandler_bonus(int sum, siginfo_t *info, void *context)
{
static char c;
static int count;
context = NULL;
signalPid = info->si_pid;
if (sum == 31)
sum = 0;
if (sum == 30)
sum = 1;
c += (sum * ft_pow_bonus(2, count++));
if (count == 8)
{
ft_putchar_bonus(c);
if (!c)
{
ft_putnbr_bonus(signalPid);
kill(signalPid,SIGUSR1);
ft_putchar_bonus('\n');
}
c = 0;
count = 0;
}
}
int main(void)
{
ft_putnbr_bonus(getpid());
ft_putchar_bonus('\n');
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = sighandler_bonus;
while (1)
{
sigaction(SIGUSR2, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
pause();
}
}
The client sends a string to the server using signals SIGUSR1 AND SIGUSR2 (I used binaries to do that) : This part is working well
but the server has to send a signal back to the sender (client) when he received the string (kill (signalPId, SIGUSR1)) and the client has to catch it with sig1handler(int sum)
: this is where i get this error "zsh: user-defined signal 1 "
should i use sigaction() instead and how can I implement it .

Server receiving and showing string from client using signals SIGUSR1 and SIGUSR2 can't handle with big amount of symbols

I had a task from school in which I need to write a client that will send string using signals (only SIGUSR1 as 1 or SIGUSR2 as 0) to server, which then should display this string. The problem is that server can normally handle only a little amount of symbols. In other cases it pauses with client or just shows weird symbols. I've tried to write in different ways using global variable in client for confirmation from server (with and without pausing the client), using usleep()(100/600/1000/10000), using pause(), result is always the same as when I fast call client again and again.
I'm writing it using VirtualBox Ubuntu.
UPD: Problem solved using sleep (5) instead of pause() in client and increasing usleep() up to 1000
Client:
#include "minitalk.h"
int g_recieve;
void sending_bits(char c, int pid)
{
int i;
i = 128;
while(i >= 1)
{
if (g_recieve == 1)
{
if (i & c)
{
if (kill(pid, SIGUSR1) == -1)
errors("Error in sending signal!\n");
}
else
{
if (kill(pid, SIGUSR2) == -1)
errors("Error in sending signal!\n");
}
i /= 2;
g_recieve = 0;
}
//usleep(600);
}
}
int send_str(int pid, char *s)
{
int i;
i = 0;
while (s[i])
{
sending_bits(s[i], pid);
i++;
}
return (0);
}
void cl_handler(int signum, siginfo_t *siginfo, void *context)
{
(void)context;
(void)siginfo;
(void)signum;
g_recieve = 1;
write(1, "Recieved signal from server\n", 28);
return ;
}
int main(int argc, char **argv)
{
struct sigaction sigac;
g_recieve = 1;
sigemptyset(&sigac.sa_mask);
sigaddset(&sigac.sa_mask, SIGINT);
sigaddset(&sigac.sa_mask, SIGQUIT);
sigaddset(&sigac.sa_mask, SIGUSR1);
sigac.sa_flags = SA_SIGINFO;
sigac.sa_sigaction = cl_handler;
if (sigaction(SIGUSR2, &sigac, NULL) == -1)
errors("Error in client sigaction\n");
if (ft_atoi(argv[1]) < 0)
errors("Wrong PID!\n");
if (argc == 3)
send_str(ft_atoi(argv[1]), argv[2]);
else
errors("Wrong arguments!\n");
while (1)
pause ();
return (0);
}
Server:
#include "minitalk.h"
void sv_handler(int signum, siginfo_t *siginfo, void *unused)
{
static int ascii = 0;
static int power = 0;
(void)unused;
if (signum == SIGUSR1)
ascii += (128 >> power);
power += 1;
if (power == 8)
{
ft_putchar(ascii);
power = 0;
ascii = 0;
}
if (siginfo->si_pid == 0)
errors("Server didn't get client's PID\n");
if (kill(siginfo->si_pid, SIGUSR2) == -1)
errors("Error in returning signal!\n");
}
int main(int argc, char **argv)
{
struct sigaction sigac;
(void)argv;
if (argc != 1)
errors("Error arguments\n");
write(1, "Server started!\nPID: ", 21);
ft_putnbr(getpid());
write(1, "\n", 1);
sigemptyset(&sigac.sa_mask);
//sigaddset(&sigac.sa_mask, SIGINT);
//sigaddset(&sigac.sa_mask, SIGQUIT);
sigac.sa_flags = SA_SIGINFO;
sigac.sa_sigaction = sv_handler;
if ((sigaction(SIGUSR1, &sigac, 0)) == -1)
errors("Error sigaction\n");
if ((sigaction(SIGUSR2, &sigac, 0)) == -1)
errors("Error sigaction\n");
while (1)
pause();
return (0);
}
Problem solved using sleep(5) instead of pause() in client and increasing usleep() in client up to 1000.

Child process not being generated and program seems to get caught in infinite loop

I am experimenting with signals forking but I am not sure what is going on with my code.
I should get 3 total processes. 1 parent 1 child and 1 grandchild. I decrement the level variable by 1 each time I make a fork so the program should terminate.
I don't understand why the program isn't generating any child processes. When I do ps aux| grep selfCaller I only ever see 1 process being run at a time.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
const int TEXT_LEN = 16;
const int NUM_SECS_TO_RUN = 30;
#define PROGNAME "selfCaller"
int numTimesCalled[3]
= {0,0,0};
pid_t pidToSignal = -1;
pid_t childPid = -1;
int level = +2;
int shouldRun = 1;
void sigAlarmHandler(int sig){
printf("Process %d: called level 0\n",level);
int w = rand() % 10 + 1;
alarm(w);
numTimesCalled[0]++;
if(level != 2){
pid_t pid = getppid();
kill(SIGUSR1, pid);
}
}
void sigUs1Handler(int sig){
printf("Process %d: called level 1\n",level);
numTimesCalled[1]++;
if(level != 2){
pid_t pid = getppid();
kill(SIGUSR2, pid);
}
}
void sigUs2Handler(int sig){
printf("Process %d: called level 2\n",level);
numTimesCalled[2]++;
}
void sigIntHandler(int sig){
shouldRun = 0;
}
int main (int argc,
char* argv[]
)
{
int comm;
if (argc > 1){
comm = strtol(argv[1], NULL, 0);
}
if (comm == 0 || comm == 1){
level = comm;
}
srand(getpid());
struct sigaction act;
memset(&act, '\0', sizeof(act));
act.sa_handler = sigAlarmHandler;
sigaction(SIGALRM, &act, NULL);
act.sa_handler = sigAlarmHandler;
sigaction(SIGUSR1, &act, NULL);
act.sa_handler = sigUs1Handler;
sigaction(SIGUSR2, &act, NULL);
act.sa_handler = sigIntHandler;
sigaction(SIGINT, &act, NULL);
// alarm(0);
pid_t pi;
if(level > 0){
pi = fork();
}
printf("pid is %d", pi);
if (pi ==-1){
exit(EXIT_FAILURE);
}
char text[TEXT_LEN];
if(pi == 0){
printf("This is the child");
int r;
snprintf(text,TEXT_LEN,"%d",level-1);
r =execl(PROGNAME, text, NULL);
if (r==-1){
fprintf(stderr,"Cannot find %s\n",PROGNAME);
exit(EXIT_FAILURE);
}
}
if (level == 2)
{
int i;
for (i = 0; i < NUM_SECS_TO_RUN; i++)
{
sleep(1);
}
}
else
{
pidToSignal = getppid();
while (shouldRun)
{
sleep(1);
}
}
printf("Level %d: %d %d %d\n",level,
numTimesCalled[0],numTimesCalled[1],numTimesCalled[2]
);
return(EXIT_SUCCESS);
}

Processes synchronization with message queues and signals

I have to create three processes:
Reading expression like 1+3+5+12
Checking if expression has correct syntax
Adding numbers and displaying them
Data between processes is shared using pipes mechanism. Processes synchronization uses message queues and signals.I also should be able to manually send signals to each process through console.
The problem I am running into this is that all processes seem to run randomly. Why is that, what's wrong here? It should work...
This is the whole code that compiles correctly:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define SIZEBUFF 256
// Signal handling for each process
void h_sig1(int signo);
void h_sig2(int signo);
void h_sig3(int signo);
void h_S4(int signo);
// Processes functions
void process1(void);
void process2(void);
void process3(void);
// helper functions
bool isInteger(double val);
static pid_t P1, P2, P3; // PIDs for each process
int P; // parent PID
int pfd12[2], pfd23[2]; // Pipes between processes 1-2 and 2-3
int providePIDY1[2], providePIDY2[2]; // provide all PIDs to 1/2 process
// message in message queue
typedef struct
{
long type;
int sigNum;
} message;
int queue_ID;
int main(void)
{
P = getpid();
// Message queue created
if ((queue_ID = msgget(IPC_PRIVATE,IPC_CREAT|0666)) < 0)
{
printf("msgget\n");
return 1;
}
if((P1 = fork()) == 0)
{
P1 = getpid();
process1();
}
else if((P2 = fork()) == 0)
{
P2 = getpid();
process2();
}
else if((P3 = fork()) == 0)
{
P3 = getpid();
process3();
}
else
{ // Sending signals from parent through operator
// Sending PIDs to process 1
close(providePIDY1[0]);
write(providePIDY1[1], &P, sizeof(int));
write(providePIDY1[1], &P1, sizeof(int));
write(providePIDY1[1], &P2, sizeof(int));
write(providePIDY1[1], &P3, sizeof(int));
close(providePIDY1[1]);
// Sending PIDs to process 2
close(providePIDY2[0]);
write(providePIDY2[1], &P, sizeof(int));
write(providePIDY2[1], &P1, sizeof(int));
write(providePIDY2[1], &P2, sizeof(int));
write(providePIDY2[1], &P3, sizeof(int));
close(providePIDY2[1]);
printf("\nProgram options:\n");
printf("Send signal - 's'(send)\n");
printf("Display processes PIDs 'p'(pids)\n");
printf("Quit program - 'q'(quit)\n");
char choice, choice2, choice3;
while(1)
{
choice = getchar();
if(choice == 's')
{
printf("Which process is receiving the signal - 1, 2, or 3?: ");
choice2 = getchar();
choice2 = getchar();
printf("\n");
if((choice2 < 1) && (choice2 > 3))
{
printf("No such process!");
continue;
}
printf("What signal to send?:\n");
printf("1-S1(end execution)\n2-S2(pause execution)\n3-S3(renew execution)?\n ");
printf("Choice: ");
choice3 = getchar();
choice3 = getchar();
switch(choice2)
{
case '1': //nie można przechwycić sygnałów SIGKILL oraz SIGSTOP (zabicia oraz zatrzymania)
if(choice3 == '1') { kill(0,SIGCONT); kill(P1,SIGUSR1); }
if(choice3 == '2') kill(P1,SIGTSTP);
if(choice3 == '3') { kill(0,SIGCONT); kill(P3,SIGALRM); }
break;
case '2':
if(choice3 == '1') { kill(0,SIGCONT); kill(P2,SIGUSR1); }
if(choice3 == '2') kill(P2,SIGTSTP);
if(choice3 == '3') { kill(0,SIGCONT); kill(P3,SIGALRM); }
break;
case '3':
if(choice3 == '1') { kill(0,SIGCONT); kill(P3,SIGUSR1); }
if(choice3 == '2') kill(P3,SIGTSTP);
if(choice3 == '3') { kill(0,SIGCONT); kill(P3,SIGALRM); }
break;
default: printf("No such operation!!! \n\n");
}
}
if(choice == 'p')
{
// do something
}
if(choice == 'q')
{
// do something
}
}
}
}
void process1(void)
{
// Receiving PIDs
close(providePIDY1[1]);
read(providePIDY1[0], &P, sizeof(int));
read(providePIDY1[0], &P1, sizeof(int));
read(providePIDY1[0], &P2, sizeof(int));
read(providePIDY1[0], &P3, sizeof(int));
close(providePIDY1[0]);
struct sigaction act1;
act1.sa_handler = h_sig1;
sigemptyset(&act1.sa_mask);
act1.sa_flags = 0;
sigaction(SIGUSR1, &act1, 0);
sigaction(SIGTSTP, &act1, 0);
sigaction(SIGALRM, &act1, 0);
struct sigaction act;
act.sa_handler = h_S4;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
// do something
}
void process2(void)
{
close(providePIDY2[1]);
read(providePIDY2[0], &P, sizeof(int));
read(providePIDY2[0], &P1, sizeof(int));
read(providePIDY2[0], &P2, sizeof(int));
read(providePIDY2[0], &P3, sizeof(int));
close(providePIDY2[0]);
struct sigaction act2;
act2.sa_handler = h_sig2;
sigemptyset(&act2.sa_mask);
act2.sa_flags = 0;
sigaction(SIGUSR1, &act2, 0);
sigaction(SIGTSTP, &act2, 0);
sigaction(SIGALRM, &act2, 0);
struct sigaction act;
act.sa_handler = h_S4;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
// do something
}
void process3(void)
{
struct sigaction act3;
act3.sa_handler = h_sig3;
sigemptyset(&act3.sa_mask);
act3.sa_flags = 0;
sigaction(SIGUSR1, &act3, 0);
sigaction(SIGTSTP, &act3, 0);
sigaction(SIGALRM, &act3, 0);
struct sigaction act;
act.sa_handler = h_S4;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
// do something
}
void h_sig1(int signo)
{
message msg;
msg.type = P2;
msg.sigNum = signo;
kill(P2, SIGINT);
// send type of receiving signal to message queue
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
msg.type = P3;
kill(P3, SIGINT);
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
if(signo == SIGUSR1)
{
}
if(signo == SIGTSTP)
{
}
if(signo == SIGALRM)
{
}
}
void h_sig2(int signo)
{
message msg;
msg.type = P1;
msg.sigNum = signo;
kill(P1, SIGINT);
// send type of receiving signal to message queue
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
msg.type = P3;
kill(P3, SIGINT);
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
if(signo == SIGUSR1)
{
}
if(signo == SIGTSTP)
{
}
if(signo == SIGALRM)
{
}
}
void h_sig3(int signo)
{
message msg;
msg.type = P1;
msg.sigNum = signo;
kill(P1, SIGINT);
// send type of receiving signal to message queue
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
msg.type = P2;
kill(P2, SIGINT);
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
if(signo == SIGUSR1)
{
}
if(signo == SIGTSTP)
{
}
if(signo == SIGALRM)
{
}
}
void h_S4(int signo)
{
int res;
message msg;
printf("\nProcess with PID=%d received signal S4", getpid());
if(signo == SIGINT)
{
res = msgrcv(queue_ID, &msg, sizeof(msg.sigNum), msg.type, 0);
if(res >= 0)
{
if(msg.sigNum == SIGUSR1)
{
}
if(msg.sigNum == SIGTSTP)
{
}
if(msg.sigNum == SIGALRM)
{
}
}
}
}
Long version, to compile:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define SIZEBUFF 200
// Signal handling for each process
void h_sig1(int signo);
void h_sig2(int signo);
void h_sig3(int signo);
void h_S4(int signo); // signal handling for the 4th signal
// Processes functions
void process1(void);
void process2(void);
void process3(void);
// helper functions
bool isInteger(double val);
static pid_t P1, P2, P3; // PIDs for each process
int P; // parent PID
int pfd12[2], pfd23[2]; // Pipes between processes 1-2 and 2-3
int providePIDY1[2], providePIDY2[2]; // provide all PIDs to 1/2 process
// message in message queue
typedef struct
{
long type;
int sigNum;
} message;
int queue_ID;
int main(void)
{
P = getpid();
if (pipe(pfd12) == -1)
{
perror("pipe failed");
exit(1);
}
if (pipe(pfd23) == -1)
{
perror("pipe failed");
exit(1);
}
// Message queue created
if ((queue_ID = msgget(IPC_PRIVATE,IPC_CREAT|0666)) < 0)
{
printf("msgget\n");
return 1;
}
if (pipe(providePIDY1) == -1)
{
perror("pipe failed");
exit(1);
}
if (pipe(providePIDY2) == -1)
{
perror("pipe failed");
exit(1);
}
if((P1 = fork()) == 0)
{
P1 = getpid();
process1();
}
else if(P1 < 0)
{
perror("fork failed");
exit(2);
}
else if((P2 = fork()) == 0)
{
P2 = getpid();
process2();
}
else if(P2 < 0)
{
perror("fork failed");
exit(2);
}
else if((P3 = fork()) == 0)
{
P3 = getpid();
process3();
}
else if(P3 < 0)
{
perror("fork failed");
exit(2);
}
else
{ // Sending signals from parent through operator
// Sending PIDs to process 1
close(providePIDY1[0]);
write(providePIDY1[1], &P, sizeof(int));
write(providePIDY1[1], &P1, sizeof(int));
write(providePIDY1[1], &P2, sizeof(int));
write(providePIDY1[1], &P3, sizeof(int));
close(providePIDY1[1]);
// Sending PIDs to process 2
close(providePIDY2[0]);
write(providePIDY2[1], &P, sizeof(int));
write(providePIDY2[1], &P1, sizeof(int));
write(providePIDY2[1], &P2, sizeof(int));
write(providePIDY2[1], &P3, sizeof(int));
close(providePIDY2[1]);
printf("\nProgram options:\n");
printf("Send signal - 's'(send)\n");
printf("Display processes PIDs 'p'(pids)\n");
printf("Quit program - 'q'(quit)\n");
char choice, choice2, choice3;
while(1)
{
choice = getchar();
if(choice == 's')
{
printf("Which process is receiving the signal - 1, 2, or 3?: ");
choice2 = getchar();
choice2 = getchar();
printf("\n");
if((choice2 < 1) && (choice2 > 3))
{
printf("No such process!");
continue;
}
printf("What signal to send?:\n");
printf("1-S1(end execution)\n2-S2(pause execution)\n3-S3(renew execution)?\n ");
printf("Choice: ");
choice3 = getchar();
choice3 = getchar();
switch(choice2)
{
case '1': //nie można przechwycić sygnałów SIGKILL oraz SIGSTOP (zabicia oraz zatrzymania)
if(choice3 == '1') { kill(0,SIGCONT); kill(P1,SIGUSR1); }
if(choice3 == '2') kill(P1,SIGTSTP);
if(choice3 == '3') { kill(0,SIGCONT); kill(P3,SIGALRM); }
break;
case '2':
if(choice3 == '1') { kill(0,SIGCONT); kill(P2,SIGUSR1); }
if(choice3 == '2') kill(P2,SIGTSTP);
if(choice3 == '3') { kill(0,SIGCONT); kill(P3,SIGALRM); }
break;
case '3':
if(choice3 == '1') { kill(0,SIGCONT); kill(P3,SIGUSR1); }
if(choice3 == '2') kill(P3,SIGTSTP);
if(choice3 == '3') { kill(0,SIGCONT); kill(P3,SIGALRM); }
break;
default: printf("No such operation!!! \n\n");
}
}
if(choice == 'p')
{
printf("\n<Processes PIDs:>\n");
printf("P(initial process)=%d\n",P);
printf("P1(process 1)=%d\n",P1);
printf("P2(process 2)=%d\n",P2);
printf("P3(process 3)=%d\n\n",P3);
}
if(choice == 'q')
{
printf("\n<Quitting program>\n");
msgctl(queue_ID, IPC_RMID, 0);
kill(0, SIGKILL);
}
}
}
}
void process1(void)
{
int dataSize;
char buff[SIZEBUFF];
// Receiving PIDs
close(providePIDY1[1]);
read(providePIDY1[0], &P, sizeof(int));
read(providePIDY1[0], &P1, sizeof(int));
read(providePIDY1[0], &P2, sizeof(int));
read(providePIDY1[0], &P3, sizeof(int));
close(providePIDY1[0]);
printf("\n<Process 1 execution in progress>\n");
/*SIGACTION*/
struct sigaction act1;
act1.sa_handler = h_sig1;
sigemptyset(&act1.sa_mask);
act1.sa_flags = 0;
sigaction(SIGUSR1, &act1, 0);
sigaction(SIGTSTP, &act1, 0);
sigaction(SIGALRM, &act1, 0);
struct sigaction act;
act.sa_handler = h_S4;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
close(pfd12[0]);
while(1)
{
printf("Provide expr: ");
scanf("%s", buff);
if(strcmp(buff, "0") == 0)
break;
dataSize = strlen(buff) + 1; // plus NULL
if(dataSize > 0)
write(pfd12[1], &dataSize, sizeof(int));
write(pfd12[1], &buff, sizeof(char)*dataSize);
}
dataSize = 0; // info that there's no more data
write(pfd12[1], &dataSize, sizeof(int));
close(pfd12[1]);
printf("\n---Process 1 finished execution---\n");
exit(0);
}
void process2(void)
{
int dataSize;
char buff[SIZEBUFF];
char *token, *end;
int number;
const char delim[2] = "+";
//Odebranie pidow
close(providePIDY2[1]);
read(providePIDY2[0], &P, sizeof(int));
read(providePIDY2[0], &P1, sizeof(int));
read(providePIDY2[0], &P2, sizeof(int));
read(providePIDY2[0], &P3, sizeof(int));
close(providePIDY2[0]);
printf("\n<Process 2 execution in progress>\n");
/*SIGACTION*/
struct sigaction act2;
act2.sa_handler = h_sig2;
sigemptyset(&act2.sa_mask);
act2.sa_flags = 0;
sigaction(SIGUSR1, &act2, 0);
sigaction(SIGTSTP, &act2, 0);
sigaction(SIGALRM, &act2, 0);
struct sigaction act;
act.sa_handler = h_S4;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
close(pfd12[1]);
read(pfd12[0], &dataSize, sizeof(int));
if(dataSize > 0)
{
sleep(3);
read(pfd12[0], buff, dataSize);
token = strtok(buff, delim);
while( token != NULL )
{
number = strtol(token, &end, 0);
if(!isInteger(number))
break;
}
}
close(pfd12[0]);
// Sending result to process 3
close(pfd23[0]);
write(pfd23[1], &buff, sizeof(int));
close(pfd23[1]);
printf("\n---Process 2 finished execution---\n");
}
void process3(void)
{
int sum = 0;
char buff[SIZEBUFF];
char* token, *end;
int number;
const char delim[2] = "+";
/*SIGACTION*/
struct sigaction act3;
act3.sa_handler = h_sig3;
sigemptyset(&act3.sa_mask);
act3.sa_flags = 0;
sigaction(SIGUSR1, &act3, 0);
sigaction(SIGTSTP, &act3, 0);
sigaction(SIGALRM, &act3, 0);
struct sigaction act;
act.sa_handler = h_S4;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
printf("\n<Process 3 execution in progress>");
close(pfd23[1]);
read(pfd23[0], &buff, sizeof(int));
token = strtok(buff, delim);
while( token != NULL )
{
number = strtol(token, &end, 0);
sum += number;
}
printf("Sum = %d\n", sum);
close(pfd23[0]);
printf("\n---Process 3 finished execution ---\n");
printf("\n---Program finished execution---\n");
kill(getppid(),SIGKILL);
}
/*******************************************************************************************************/
/****************************************SIGNAL HANDLING (S1-S3)***********************************************/
/*******************************************************************************************************/
void h_sig1(int signo)
{
message msg;
msg.type = P2;
msg.sigNum = signo;
kill(P2, SIGINT);
// send type of receiving signal to message queue
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
msg.type = P3;
kill(P3, SIGINT);
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
if(signo == SIGUSR1)
{
printf("\nProcess 1 received signal S1\n");
printf("Terminating parent process!\n");
kill(getppid(), SIGKILL);
printf("Terminating process 1!\n");
kill(getpid(), SIGKILL);
}
if(signo == SIGTSTP)
{
printf("\nProcess 1 received signal S2\n");
printf("Pausing process 1!\n");
kill(getpid(), SIGSTOP);
}
if(signo == SIGALRM)
{
printf("\nProcess 1 received signal S3\n");
printf("Renewing execution of process 1!\n");
kill(getpid(), SIGCONT);
}
}
void h_sig2(int signo)
{
message msg;
msg.type = P1;
msg.sigNum = signo;
kill(P1, SIGINT);
// send type of receiving signal to message queue
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
msg.type = P3;
kill(P3, SIGINT);
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
if(signo == SIGUSR1)
{
printf("\nProcess 2 received signal S1\n");
printf("Terminating parent process!\n");
kill(getppid(), SIGKILL);
printf("Terminating process 2!\n");
kill(getpid(), SIGKILL);
}
if(signo == SIGTSTP)
{
printf("\nProcess 2 received signal S2\n");
printf("Pausing process 2!\n");
kill(getpid(), SIGSTOP);
}
if(signo == SIGALRM)
{
printf("\nProcess 2 received signal S3\n");
printf("Renewing execution of process 2!\n");
kill(getpid(), SIGCONT);
}
}
void h_sig3(int signo)
{
message msg;
msg.type = P1;
msg.sigNum = signo;
kill(P1, SIGINT);
// send type of receiving signal to message queue
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
msg.type = P2;
kill(P2, SIGINT);
msgsnd(queue_ID, &msg, sizeof(msg.sigNum), 0);
if(signo == SIGUSR1)
{
printf("\nProcess 3 received signal S1\n");
printf("Terminating parent process!\n");
kill(getppid(), SIGKILL);
printf("Terminating process 3!\n");
kill(getpid(), SIGKILL);
}
if(signo == SIGTSTP)
{
printf("\nProcess 3 received signal S2\n");
printf("Pausing process 3!\n");
kill(getpid(), SIGSTOP);
}
if(signo == SIGALRM)
{
printf("\nProcess 3 received signal S3\n");
printf("Renewing execution of process 3!\n");
kill(getpid(), SIGCONT);
}
}
/*******************************************************************************************************/
/****************************************Handling S4 signal***********************************/
/*******************************************************************************************************/
void h_S4(int signo)
{
int res;
message msg;
printf("\nProcess with PID=%d received signal S4", getpid());
if(signo == SIGINT)
{
res = msgrcv(queue_ID, &msg, sizeof(msg.sigNum), msg.type, 0);
if(res >= 0)
{
if(msg.sigNum == SIGUSR1)
{
printf("Terminating process\n");
kill(getpid(),SIGKILL);
}
if(msg.sigNum == SIGTSTP)
{
printf("Pausing process\n");
kill(getpid(),SIGSTOP);
}
if(msg.sigNum == SIGALRM)
{
printf("Renewing process\n");
kill(getpid(),SIGCONT);
}
}
}
}
bool isInteger(double val)
{
int truncated = (int)val;
return (val == truncated);
}
Source code analysis
There are consistency problems:
static pid_t P1, P2, P3; // PIDs for each process
int P; // parent PID
Why is P and int instead of a pid_t? Why is it global instead of static? Why is it P instead of P0? Should the whole lot be an array?
static pid_t P[4];
(There would be benefits to using an array!)
There is repetition that should be in a function invoked multiple times:
// Sending PIDs to process 1
close(providePIDY1[0]);
write(providePIDY1[1], &P, sizeof(int));
write(providePIDY1[1], &P1, sizeof(int));
write(providePIDY1[1], &P2, sizeof(int));
write(providePIDY1[1], &P3, sizeof(int));
close(providePIDY1[1]);
// Sending PIDs to process 2
close(providePIDY2[0]);
write(providePIDY2[1], &P, sizeof(int));
write(providePIDY2[1], &P1, sizeof(int));
write(providePIDY2[1], &P2, sizeof(int));
write(providePIDY2[1], &P3, sizeof(int));
close(providePIDY2[1]);
Note that there's also repetition because the P values aren't an array. There's also a possible portability liability; pid_t does not have to be the same size as int.
There are problems with checking inputs:
choice = getchar();
if(choice == 's')
Since choice is a char, you can get erroneous handling of EOF — if you bothered to test for it. You also leave a newline (at least) in the input, and don't skip leading spaces in the input. You'd likely do better with reading a line of data (fgets() or POSIX
readline()) and then using if (sscanf(buffer, " %c", &choice) != 1) { …handle error… } to get the character.
Your next input block is curious:
printf("Which process is receiving the signal - 1, 2, or 3?: ");
choice2 = getchar();
choice2 = getchar();
printf("\n");
if((choice2 < 1) && (choice2 > 3))
The first input reads the newline (assuming there were no trailing spaces, etc), and the second gets a '1', '2', or '3'. However, you test whether the input value is both less than 1 and greater than 3, and there's no known value in the universe for which both conditions are true (NaN values are unknown values). You really wanted something like:
if (choice2 < '1' || choice2 > '3')
After you've determined which signal to send (more or less), you have another block of repeated code because you used P1 etc instead of an array P.
There are chunks of repeated code in your child processes, such as the code that reads the process numbers. These should be in a function, too. The signal handling setup should probably be in a function too, though I've not spent a lot of time checking for the differences and similarities between the different process functions.
Major problem
You say the code is supposed to be processing arithmetic expressions. You have the main program loop reading choices about signal handling, but you seem to have process1() also trying to read expressions. This is bad news; it is indeterminate which of the processes will get to read any given input.
Back to the small stuff
You have:
dataSize = strlen(buff) + 1; // plus NULL
if(dataSize > 0)
write(pfd12[1], &dataSize, sizeof(int));
write(pfd12[1], &buff, sizeof(char)*dataSize);
The test is a little pointless; the minimum value that strlen() can return is 0, so the minimum value in dataSize is 1, so the condition will always be true. (Theoretically, I suppose, you could enter so much data that the size_t returned by strlen() overflows the int dataSize, but you've not allocated enough space for that to be an actual problem — your code will have had other problems before that.)
In process2(), this code is curious:
token = strtok(buff, delim);
while( token != NULL )
{
number = strtol(token, &end, 0);
if(!isInteger(number))
break;
}
There are no circumstances under which the int number; is going to be a non-integer when you scan the string with strtol(). You have a risk of overflow (sizeof(int) != sizeof(long) on 64-bit Unix systems, for example). You have a risk of not being able to interpret the remnants of floating point value (because the . is not a valid part of an integer). You'll need to rework that code.
There's a lot of repetition in the signal handling code; it should be refactored so that you need fewer functions. It'll be easier to understand in the long run. Copy'n'paste'n'edit is a very bad way of programming when the result is near clones of the code in a single program.
I'm not clear what the differences are between the two versions you show; I've not scrutinized them. You should look at how to create an MCVE (How to create a Minimal, Complete, and Verifiable Example?) or SSCCE (Short, Self-Contained, Correct Example) — two names and links for the same basic idea. I'm not sure that either lot of code qualifies as an MCVE; both versions is overkill. Just supply the compilable code.
After compilation
I've compiled the second chunk of code (saved in a file called procsync.c) on my Mac running Mac OS X 10.10.3 with GCC 5.1.0, and using the command line:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror procsync.c -o procsync
$
To my considerable surprise, the code compiled under those very stringent options with no complaints — that is something I very seldom see in code on SO.
Congratulations!
(But there are still the other issues to worry about.)

process communication with signls

I am trying to write a C program which has some number of processes. One of them sends a random signal in the range SIGRTMIN and SIGRTMAX to all other processes but I want this signal will be ignored in main process.I used the global variable to have randomized signal to ignore with SIG_IGN. It looks It is not helping because the main stops with real-time signal when wants to ignore the first randomized signal.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
volatile sig_atomic_t disarming_signal = 0;
void disarming_handler (int sig) {
disarming_signal = sig;
fprintf(stderr,"signal %d is handeled", disarming_signal);
}
int rand_range(int min_n, int max_n){
int rand_n = rand() % (max_n - min_n) + min_n;
return rand_n;
}
int sethandler (void (*f)(int), int sigNo) {
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = f;
if (-1==sigaction(sigNo, &act, NULL))
return -1;
return 0;
}
void sigchld_handler(int sig){
pid_t pid;
for(;;){
pid=waitpid(0, NULL, WNOHANG);
if(pid==0) return;
if(pid<=0) {
if(errno==ECHILD) return;
perror("waitpid:");
exit(EXIT_FAILURE);
}
}
}
void usage(){
fprintf(stderr,"USAGE: sappartherroryst n\n");
fprintf(stderr,"n - number of Therrorysts\n");
}
void therroryst_work(){
int s,k,t;
srand(getpid());
s = rand_range(SIGRTMIN, SIGRTMAX);
t = rand_range(10, 20);
k = t;
if(sethandler(disarming_handler, s)){
perror("Seting therroryst handeler");
exit(EXIT_FAILURE);
}
fprintf(stderr, "[%d] I am therroryst. My disarming signal is [%d]. I will wait [%d] Sec.\n", getpid(), s, t);
while(k>0) {
k=sleep(k);
if(disarming_signal == s){
fprintf(stderr, "I got signal [%d]\n.",disarming_signal);
return ;
}
}
fprintf(stderr, "[%d] KABOOM\n",getpid());
exit(EXIT_SUCCESS);
}
void create_therrorysts(int n){
while(n-->0){
switch(fork()) {
case 0:
therroryst_work();
exit(EXIT_SUCCESS);
case -1:
perror("Fork():");
exit(EXIT_FAILURE);
}
}
}
void sapper_work(){
int sig_dis, i;
struct timespec t, tn = {1,0};
fprintf(stderr,"[%d] I am sapper.\n", getpid());
for(i=0;i<10;i++){
for(t=tn;nanosleep(&t,&t););
sig_dis = rand_range(SIGRTMIN, SIGRTMAX);
if(kill(0, sig_dis)<0){
perror("Disarming_send\n");
exit(EXIT_FAILURE);
}
fprintf(stderr,"I sended signal [%d].\n",sig_dis);
disarming_signal = sig_dis;
}
fprintf(stderr, "end of sending");
exit(EXIT_SUCCESS);
}
void create_sapper(){
switch(fork()) {
case 0:
sapper_work();
exit(EXIT_SUCCESS);
case -1:
perror("Fork():");
exit(EXIT_FAILURE);
}
}
int main(int argc, char** argv){
int n;
pid_t pid;
if(argc != 2){
usage();
return EXIT_FAILURE;
}
n = atoi(argv[1]);
if(n <= 0){
usage();
return EXIT_FAILURE;
}
if(sethandler(sigchld_handler, SIGCHLD)) {
perror("Seting parent SIGCHLD:");
exit(EXIT_FAILURE);
}
create_therrorysts(n);
create_sapper();
sleep(5);
for(;;) {
if(sethandler(SIG_IGN, disarming_signal)){
perror("Seting parent disarming111");
exit(EXIT_FAILURE);
}
}
for(;;){
pid=wait(NULL);
if(pid<0)
switch (errno){
case ECHILD:
return EXIT_SUCCESS;
case EINTR:
continue;
default:
perror("wait:");
exit(EXIT_FAILURE);
}
}
return EXIT_SUCCESS;
}
You have sleep(5) after the create_sapper and before sethandler(IGN). That means it's very likely that the signal is sent before your main process has ignored it.
EDIT: Adding comment from Jonathan Leffler into this answer as it is equally (or even more) important:
There's also a problem with setting the signal handler even if you put the sleep() after that loop - the parent doesn't get to see what the child chooses as disarming_signal.

Resources