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 .
Related
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.
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);
...
}
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);
}
I have a few children process, I need to send a signal to the parent and make sure the signal was received before continuing
#define CHILD 0
int n = 0;
void handler(int sig) {
n--;
signal(SIGCHLD, handler);
}
int main(int argc, char * argv[]) {
int p ;
signal(SIGCHLD, handler);
if(argc == 2) {
int k = atoi(argv[1]);
n = k;
while(k-- != 0) {
p = fork();
if(p == CHILD) {
srand(time(NULL));
int r = 1 +(rand()%10);
printf("No:%d %d Child PID: %d times.%d\n",k,n, getpid(),r);
// int rai = raise(SIGCHLD);
printf("rai: %d %d\n", rai, n);
sleep(r);
exit(1);
}
}
} else {
puts("Please provide k num of zombie to be generated\n");
}
while(p > CHILD && n > 0) {
printf("sleeping 2 %d\n", n);
sleep(2);
}
return EXIT_SUCCESS;
}
How can I be sure that the parent catch all the SIGCHILD signals
Imports were omitted on purpose
I'm trying to learn how to work with fork() to create new processes and pipes to communicate with each process. Let's say I have a list that contains 20 words, and I create 3 processes. Now, I need to distribute the words between the processes using pipes, and the each process will sort the list of words it receives. The way I want to achieve this is like this:
Word1 => Process1
Word2 => Process2
Word3 => Process3
Word4 => Process1
Word5 => Process2
Word6 => Process3
.
.
.
So each process will have a list of words to sort, and eventually I'll use MergeSort to merge all the sorted lists returned by each process. I'm not sure how to use pipes to communicate with each process (e.g. feed each process with a word). Any help that would put me on the right track would be appreciated.
Try this code for size. It uses a fixed number of child processes, but you can change that number by adjusting the enum MAX_KIDS (it was mostly tested with that set at 3; I later changed it to 5 just to make sure).
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct Child
{
FILE *fp_to;
FILE *fp_from;
pid_t pid;
} Child;
enum { P_READ, P_WRITE }; /* Read, write descriptor of a pipe */
enum { MAX_LINE = 4096 };
static void be_childish(void);
static void distribute(size_t nkids, Child *kids);
static void err_exit(const char *fmt, ...);
static void merge(size_t nkids, Child *kids);
static void wait_for_kids(size_t nkids, Child *kids);
static int make_kid(Child *kid)
{
int pipe1[2]; /* From parent to child */
int pipe2[2]; /* From child to parent */
if (pipe(pipe1) != 0)
return -1;
if (pipe(pipe2) != 0)
{
close(pipe1[P_READ]);
close(pipe1[P_WRITE]);
return -1;
}
if ((kid->pid = fork()) < 0)
{
close(pipe1[P_READ]);
close(pipe1[P_WRITE]);
close(pipe2[P_READ]);
close(pipe2[P_WRITE]);
return -1;
}
else if (kid->pid == 0)
{
dup2(pipe1[P_READ], STDIN_FILENO);
dup2(pipe2[P_WRITE], STDOUT_FILENO);
close(pipe1[P_READ]);
close(pipe1[P_WRITE]);
close(pipe2[P_READ]);
close(pipe2[P_WRITE]);
/* Reads standard input from parent; writes standard output to parent */
be_childish();
exit(0);
}
else
{
kid->fp_to = fdopen(pipe1[P_WRITE], "w");
kid->fp_from = fdopen(pipe2[P_READ], "r");
close(pipe1[P_READ]);
close(pipe2[P_WRITE]);
return 0;
}
}
int main(void)
{
enum { NUM_KIDS = 5 };
Child kids[NUM_KIDS];
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &act, 0);
for (int i = 0; i < NUM_KIDS; i++)
{
if (make_kid(&kids[i]) != 0)
err_exit("Fault starting child %d\n", i);
}
distribute(NUM_KIDS, kids);
merge(NUM_KIDS, kids);
wait_for_kids(NUM_KIDS, kids);
return(0);
}
static void err_exit(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(1);
}
static int qs_compare(const void *v1, const void *v2)
{
const char *s1 = *(char **)v1;
const char *s2 = *(char **)v2;
return(strcmp(s1, s2));
}
static char *estrdup(const char *str)
{
size_t len = strlen(str) + 1;
char *out = malloc(len);
if (out == 0)
err_exit("Out of memory!\n");
memmove(out, str, len);
return(out);
}
static void be_childish(void)
{
char **lines = 0;
size_t num_lines = 0;
size_t max_lines = 0;
char input[MAX_LINE];
while (fgets(input, sizeof(input), stdin) != 0)
{
if (num_lines >= max_lines)
{
size_t n = (2 * max_lines + 2);
void *space = realloc(lines, n * sizeof(char *));
if (space == 0)
err_exit("Out of memory!\n");
lines = space;
max_lines = n;
}
lines[num_lines++] = estrdup(input);
}
qsort(lines, num_lines, sizeof(char *), qs_compare);
for (size_t i = 0; i < num_lines; i++)
{
if (fputs(lines[i], stdout) == EOF)
err_exit("Short write to parent from %d\n", (int)getpid());
}
exit(0);
}
static void distribute(size_t nkids, Child *kids)
{
char input[MAX_LINE];
size_t n = 0;
while (fgets(input, sizeof(input), stdin) != 0)
{
if (fputs(input, kids[n].fp_to) == EOF)
err_exit("Short write to child %d\n", (int)kids[n].pid);
if (++n >= nkids)
n = 0;
}
/* Close pipes to children - let's them get on with sorting */
for (size_t i = 0; i < nkids; i++)
{
fclose(kids[i].fp_to);
kids[i].fp_to = 0;
}
}
static void read_line(Child *kid, char *buffer, size_t maxlen, int *length)
{
if (fgets(buffer, maxlen, kid->fp_from) != 0)
{
*length = strlen(buffer);
buffer[*length] = '\0';
}
else
{
buffer[0] = '\0';
*length = -1;
fclose(kid->fp_from);
kid->fp_from = 0;
}
}
static int not_all_done(size_t nkids, int *lengths)
{
for (size_t i = 0; i < nkids; i++)
{
if (lengths[i] > 0)
return 1;
}
return 0;
}
static void min_line(size_t nkids, int *len, char **lines, size_t maxlen,
Child *kids, char *output)
{
size_t min_kid = 0;
char *min_str = 0;
for (size_t i = 0; i < nkids; i++)
{
if (len[i] <= 0)
continue;
if (min_str == 0 || strcmp(min_str, lines[i]) > 0)
{
min_str = lines[i];
min_kid = i;
}
}
strcpy(output, min_str);
read_line(&kids[min_kid], lines[min_kid], maxlen, &len[min_kid]);
}
static void merge(size_t nkids, Child *kids)
{
char line_data[nkids][MAX_LINE];
char *lines[nkids];
int len[nkids];
char output[MAX_LINE];
for (size_t i = 0; i < nkids; i++)
lines[i] = line_data[i];
/* Preload first line from each kid */
for (size_t i = 0; i < nkids; i++)
read_line(&kids[i], lines[i], MAX_LINE, &len[i]);
while (not_all_done(nkids, len))
{
min_line(nkids, len, lines, MAX_LINE, kids, output);
fputs(output, stdout);
}
}
static void wait_for_kids(size_t nkids, Child *kids)
{
int pid;
int status;
while ((pid = waitpid(-1, &status, 0)) != -1)
{
for (size_t i = 0; i < nkids; i++)
{
if (pid == kids[i].pid)
kids[i].pid = -1;
}
}
/* This check loop is not really necessary */
for (size_t i = 0; i < nkids; i++)
{
if (kids[i].pid != -1)
err_exit("Child %d died without being tracked\n", (int)kids[i].pid);
}
}
The overall picture is usually:
pid_t pids[3];
int fd[3][2];
int i;
for (i = 0; i < 3; ++i) {
/* create the pipe */
if (pipe(fd[i]) < 0) {
perror("pipe error");
exit(1);
}
/* fork the child */
pid[i] = fork();
if (pid[i] < 0) {
perror("fork error");
} else if (pid[i] > 0) {
/* in parent process */
/* close reading end */
close(fd[i][0]);
} else {
/* in child process */
/* close writing end */
close(fd[i][1]);
/* read from parent */
read(fd[i][0], line, max);
...
}
}
/* in parent process */
char words[100][10] = {...};
int j, child = 0;
/* for all words */
for (j = 0; j < 100; ++j) {
/* write to child */
write(fd[child][1], words[j], strlen(words[j]));
...
++child;
if (child >= 3)
child = 0;
}
Duplicate the pipe part for communicating back from child to parent. Be careful not to deadlock when parent and child are trying to communicate in both directions simultaneously.
There's nothing magical about pipes - they are just a communication medium with two endpoints. The logic goes approximately:
Create 3 pipes and hold onto one endpoint. Fork three times, and get each of those forked children to hold onto the other end of the pipe. The child then goes into a read loop, waiting for input and writing back output. The parent can round-robin all outputs, then do a round-robin read of inputs. This isn't the nicest strategy, but it's by far the simplest. i.e.,
while there is work left to do:
for i in 1..3
write current work unit to pipe[i]
for i in 1..3
read back response from pipe[i]
A given child just looks like this:
while(input = read from pipe)
result = do work on input
write result to pipe
The next step would be doing your read-back in the parent process in an asynchronous, non-blocking manner (possibly using select, or just a busy-wait polling loop). This requires the children to report back which task they are returning a result for, because the ordering could get messy (i.e., you can no longer rely on the first work unit you send being the first response you get). Welcome to the fun world of concurrency bugs.
Given the somewhat underspecified nature of your question, I hope this is somehow useful.