EDIT: Thanks for the suggestions given so far. I changed the program and now the parent handles some of the signals, but it looks like it doesn't handle all of them. New code and results are posted below.
EDIT2: I changed the random number generation as proposed. Now the parent catches only two signals but it always catches the right bits (two last bits).
"Unfortunately, I am not experienced in C POSIX and I have to write a program that will take one argument (filename containing a binary number) and parse this file. Each bit denoted in the file means that one child should be created (each bit is dedicated to one child).
The value of the bit (0 or 1) decides which signals should be sent to the parent (0 - SIGUSR1, 1 - SIGUSR2).
The child process should choose a random interval (10-200ms) and send appropriate signal to the parent.
The parent should receive the signals and print the last 5 bits received every time a new signal arrives.
The final step is the matching process - the parent checks the received signals (bits assigned to SIGUSR1 or SIGUSR2) and if there's a match it prints SUCCESS. If there's no match (whenever a wrong bit is sent - compared to the file) the parent starts matching from the beginning."
The updated version:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <signal.h>
volatile sig_atomic_t last_signal = 0;
char * str;
char * received;
int count = 0;
#define ERR(source) (fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
perror(source),kill(0,SIGKILL),\
exit(EXIT_FAILURE))
void 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)) ERR("sigaction");
}
char *readFile(char *fileName)
{
FILE *file = fopen(fileName, "r");
char *code;
size_t n = 0;
int c;
if (file == NULL) return NULL; //could not open file
fseek(file, 0, SEEK_END);
long f_size = ftell(file);
fseek(file, 0, SEEK_SET);
code = malloc(f_size);
received = malloc(f_size);
while ((c = fgetc(file)) != EOF) {
code[n++] = (char)c;
}
code[n] = '\0';
return code;
}
void append(char* s, char c)
{
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
static void sig_handle(int signum)
{
last_signal = signum;
}
void child_w(int number_of)
{
if(str[number_of] == '0')
{
if (kill(getppid(), SIGUSR1)==0) printf("[SIGUSR1] sent \n");
else
{
printf("ERROR kill. \n");
exit(EXIT_FAILURE);
}
}
if(str[number_of] == '1')
{
if (kill(getppid(), SIGUSR2) == 0) printf("[SIGUSR2] sent \n");
else
{
printf("ERROR kill. \n");
exit(EXIT_FAILURE);
}
}
}
void create_children(int n)
{
pid_t s;
int j = n;
int time = rand() % 191 + 10; // range 10 - 200
struct timespec time_wait = { .tv_sec = 0, .tv_nsec = time * 1000000L };
while(j-->0)
{
nanosleep(&time_wait, NULL);
if((s=fork())<0) ERR("Fork ERROR");
if(!s) {
printf("Child %d started ", j);
printf("with bit: %c \n", str[j]);
child_w(j);
exit(EXIT_SUCCESS);
}
}
}
void parent_w(sigset_t oldmask)
{
int count = 0;
int match = 0;
while(1)
{
last_signal = 0;
while(last_signal != SIGUSR1 && last_signal != SIGUSR2)
{
sigsuspend(&oldmask);
}
printf("\n");
if(last_signal == SIGUSR1)
{
received[count] = '0';
for(int i=0; i<sizeof(received); ++i)
{
printf("%c ", received[i]);
}
count++;
}
else if(last_signal == SIGUSR2)
{
received[count] = '1';
for(int i=0; i<sizeof(received); ++i)
{
printf("%c ", received[i]);
}
count++;
}
printf("\n");
}
}
int main(int argc, char ** argv)
{
char filename[250];
if(argc!=2)
{
printf("Provide one parameter - filename. \n");
return EXIT_FAILURE;
}
strcpy(filename, argv[1]);
str = readFile(filename);
printf("FILE: ");
for(int i=0; i<sizeof(str); ++i)
{
printf("%c ", str[i]);
}
printf("\n");
for(int i=0; i<sizeof(received); ++i)
{
received[i] = '-';
}
sethandler(sig_handle, SIGUSR1);
sethandler(sig_handle, SIGUSR2);
sigset_t mask, oldmask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
create_children(sizeof(str));
parent_w(oldmask);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
free(str);
free(received);
return EXIT_SUCCESS;
}
Now the output always looks like this:
FILE: 1 0 0 1 1 0 1 0
Child 7 started with bit: 0
[SIGUSR1] sent
Child 6 started with bit: 1
[SIGUSR2] sent
Child 5 started with bit: 0
[SIGUSR1] sent
Child 4 started with bit: 1
[SIGUSR2] sent
Child 3 started with bit: 1
[SIGUSR2] sent
Child 2 started with bit: 0
[SIGUSR1] sent
Child 1 started with bit: 0
[SIGUSR1] sent
0 - - - - - - -
Child 0 started with bit: 1
[SIGUSR2] sent
0 1 - - - - - -
Any further suggestions will be appreciated :).
signal(SIGUSR2, sig_handle2);tomain().TheSIGUSR1is handled cause you only dosignal(SIGUSR1, sig_handle1);fromparent_w(and in a loop, remove it form the loop), so only SIGUSR1 handler is registered. - KamilCuksigaction()appropriately then you don't need to keep re-registering your handlers. They will stick, if you specify they should do. The same is not necessarily true for thesignal()function, which indeed you should avoid for most purposes. - John Bollinger