This is from my study guide. From my perspective this is almost done but I can't put it working in the way I want.
The exercise is:
given an string fork X times and print one character per child until the the string finish.
This is the code and compiles:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <dirent.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
// SOME PROGRAM CONSTANTS
#define CHILD_QUANTITY 5
#define FIFO_FILE "/tmp/printer.fifo"
#define STRING_TO_PRINT "hola mundo como estas!!!!"
#define DELAY_TIME 2 // two seconds
// SOME GLOBAL VARIABLES
int fdfifo, next_printer = 0, next_char = 0;
pid_t printers[CHILD_QUANTITY];
void process_call_printer(int sig) {
char char_to_print;
if (read(fdfifo, &char_to_print, sizeof(char)) == -1) {
perror(__FUNCTION__);
}
// print the char
printf("[%d] -> %c\n", getpid(), char_to_print);
// alert the parent process about it
kill(getppid(), SIGUSR2);
// just wait for another signal
while(1) {
pause();
}
}
void process_call_hub(int sig) {
pid_t printer;
if (next_char < strlen(STRING_TO_PRINT)) {
if (write(fdfifo, &STRING_TO_PRINT[next_char], sizeof(char)) == -1) {
perror(__FUNCTION__);
}
alarm(DELAY_TIME);
if (next_printer >= CHILD_QUANTITY) {
next_printer = 0;
}
printer = printers[next_printer];
next_printer++;
next_char++;
printf("sending char %c to the printer %d\n", STRING_TO_PRINT[next_char - 1], next_printer - 1);
kill(printer, SIGUSR1);
}
else {
kill(getpid(), SIGQUIT);
}
}
void process_callback(int sig) {
// alarm(0);
printf("a callback function call\n");
// kill(getpid(), SIGALRM);
// while(1) {
// pause();
// }
}
void system_shutdown(int sig) {
printf("SIGQUIT recived...terminating\n");
if (unlink(FIFO_FILE) == -1) {
perror(__FUNCTION__);
}
close(fdfifo);
}
int main(void) {
pid_t pid;
int i;
if (mkfifo(FIFO_FILE, 0777) == -1) {
perror("pipe()");
return -1;
}
fdfifo = open(FIFO_FILE, O_RDWR, 0777);
if (fdfifo == -1) {
perror("open()");
return -2;
}
for (i = 0; i < CHILD_QUANTITY; i++) {
pid = fork();
printers[i] = pid;
switch(pid) {
case -1:
perror("Error\n");
break;
case 0:
// printer
signal(SIGUSR1, process_call_printer);
while(1) {
pause();
}
break;
default:
// hub
// do nothing.. we will figure out later...
break;
}
}
signal(SIGALRM, process_call_hub);
signal(SIGQUIT, system_shutdown);
signal(SIGUSR2, process_callback);
alarm(DELAY_TIME);
while(1) {
pause();
}
}
and this is the output I got
gabriel#GaboMac:20090918$ ./threaded_printer
sending char h to the printer 0
[1397] -> h
a callback function call
sending char o to the printer 1
[1398] -> o
a callback function call
sending char l to the printer 2
[1399] -> l
a callback function call
sending char a to the printer 3
[1400] -> a
a callback function call
sending char to the printer 4
[1401] ->
a callback function call
sending char m to the printer 0
sending char u to the printer 1
sending char n to the printer 2
sending char d to the printer 3
sending char o to the printer 4
sending char to the printer 0
sending char c to the printer 1
sending char o to the printer 2
sending char m to the printer 3
sending char o to the printer 4
sending char to the printer 0
sending char e to the printer 1
sending char s to the printer 2
sending char t to the printer 3
sending char a to the printer 4
sending char s to the printer 0
sending char ! to the printer 1
sending char ! to the printer 2
sending char ! to the printer 3
sending char ! to the printer 4
SIGQUIT recived...terminating
All echos should be like the five first ones.
Any idea?
Firstly, this is terrible code. You should never do real work in a signal handler. This program has its main loop in a signal handler - not good!
The problem is that your child processes do their work in the process_call_printer() signal handler, but that function never returns. It ends with
// just wait for another signal
while(1) {
pause();
}
Well, it's going to wait forever for another signal because a signal is blocked while it is being handled. So your child is not going to receive any more SIGUSR1s until it's finished processing the first one - and it never does.
That's why your child processes stop responding after they've handled the first signal.
Now, seriously. Go and rewrite this with the bare minimum of signal handling. It's usually done something like this...
int got_signal;
void handler(int) {
got_signal = 1;
}
int main() {
...
/* Wait for signal */
got_signal = 0;
while(!got_signal) {
sleep(1);
}
/* Signal has arrived - do something... */
...
}
Related
I wrote a program deamon which copy files with one folder to another .I have to implement SIGUSR1 which immediately wake up the daemon by sending him a SIGUSR1 signal. I do not know what I did wrong ,I use command kill -SIGUSR1 ,maybe wrong command?.Somebody know what is wrong with this code ?I did not have any warning after compiled this program,but just nothing happend
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#define _XOPEN_SOURCE ;
int recursion = 0; //1 if enabled, otherwise 0
int sleepTime = 300;
int fileLimit = 0;
int signaL = 0;
int exitSignal = 0;
int buffer = 1000;
//Returns 0 if arguments are correct otherwise returns 1
int readArguments(int number, char **argv, char *source, char *goal);
int checkFileType(struct stat file);
int copy(char *source, char *target, mode_t mask);
int copy_map(char *source, char *target, struct stat *Source);
void syncCopy(char *source, char *target);
void syncRemove(char *source, char *target);
void my_handler(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR1\n");
signaL = 1;
}
void exitFunction(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR2\n");
exitSignal = 1;
}
int main(int argc, char **argv)
{
//char tables for paths
char source[500], goal[500];
struct stat Source, Goal;
struct sigaction my_action, old_action;
//checking and reading arguments
if (readArguments(argc, argv, source, goal) == 1)
exit(-1);
//checking paths
//checking if argv[1] and argv[2] are existing paths
if (lstat(source, &Source) != 0 || lstat(goal, &Goal) != 0) //bad result
{
printf("One of the paths or both dont exist\n");
exit(-1);
}
if (checkFileType(Source) != 0)
{
printf("Source path is not path to folder");
exit(-1);
}
if (checkFileType(Goal) != 0)
{
printf("Goal path is not path to folder");
exit(-1);
}
//forking the parent process
pid_t pid;
// Fork off the parent process and create new
pid = fork();
//if failure
if (pid < 0)
{
exit(-1);
}
// if it is native process
else if (pid > 0)
{
return 0;
}
//if pid==0 then it is childs process
//now we have to umask in order to write to any files(for exmaple logs)
umask(0);
openlog("logFile", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Deamon has just started running\n");
pid_t sid = setsid();
if (sid < 0)
{
syslog(LOG_ERR, "Error with session opening\n");
exit(-1);
}
//SIGNAL SIGUSR1
my_action.sa_handler = my_handler;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR1, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR1 signal\n");
exit(-1);
}
//SIGNAL SIGUSR2 for exiting daemon
my_action.sa_handler = exitFunction;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR2, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR2 signal\n");
exit(-1);
}
while (!exitSignal)
{
sleep(sleepTime);
switch (signaL)
{
case 0:
syslog(LOG_INFO, "Demon started working after %ds\n", sleepTime);
break;
case 1:
{
syslog(LOG_INFO, "Demon started working after SIGUSR1 signal\n");
signaL = 0; //Need to reeset signaL
break;
}
}
syncCopy(source, goal);
syncRemove(source, goal);
syslog(LOG_INFO, "Demon has just gone to sleep");
}
//at the end of program we need to close log using
syslog(LOG_INFO, "Demon has stopped\n");
closelog();
return 0;
}
Use command as kill -10 <pid> for SIGUSR1 and kill -12 <pid> for SIGUSR2.
kill -l // command to know the signal number.
Also make variable signaL , exitSignal as volatile sig_atomic_t type.
WHY volatile?
when a global variable updated in signal handler is periodically checked in some other function for appropriate action, we should always declare them using the volatile attribute in order to prevent the compiler from performing optimizations that result in the variable being stored in a register. In worst case, updated value of variable(updated in handler context) won't be visible to function polling for the variable.
WHY sig_atomic_t?
Reading and writing global variables may involve more than one machine- language instruction, and a signal handler may interrupt the main program in the middle of such an instruction sequence. (We say that access to the variable is nonatomic.) For this reason, the C language standards and SUSv3 specify an integer data type, sig_atomic_t, for which reads and writes are guaranteed to be atomic. Thus, a global flag variable that is shared between the main program and a signal handler should be declared as follows:
volatile sig_atomic_t signaL;
I'm working on signal project get a file with 0, increase to the input (ex ./count 300 sample.txt) by using sync signals p1->p2->p3->p1, after they increase number by 1, the fall in to sleep and call next one.
but I got stuck with two problems
how to and where to implement increasing number process, in signal handling or main( 0 -> 1 -> 2 ... input )
don't know how to implement with sigwait() or sigprocmask() what's the difference? . can i choose either one to guarantee that they are synchronized? or should I just use sleep?
belows are code that I've been working on so far.
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
void sig_usr1(int signo)
{
char a;
sigset_t sigset, oldset;
sigemptyset (&oldset);
sigemptyset (&sigset);
sigaddset(&sigset, SIGUSR1);
sigprocmask(SIG_BLOCK, &sigset, &oldset);
fd =open("./sample.txt",O_RDWR);
pread (fd, a, sizeof(a));
if (argv[0]>a)
{a ++;
truncate ("./sample.txt", 0);
write(fd, a, sizeof(a));
}
}
int main (int argc, char** argv)
{
int fd;
int num=0;
struct sigaction usrsig ;
if(!(argv[0]>0))
printf("insert positive integer");
fd = open("./sample.txt",O_RDWR|O_CREAT|O_TRUNC);
write(fd, num ,sizeof(num);
pid_t child[3];
usrsig.sa_handler =sig_usr; // Parent
sigemptyset(&usrsig.sa_mask);
usrsig1.sa_flags = 0;
sigaction(SIGUSR1,&usrsig, 0);
for ( i=0; i<3; i++)
{
child[i] = fork();
if(child[i] == 0)
break;
}
pid_t prev;
if(i ==0) prev = getppid();
else prev = child[i-1];
kill(pid_prev, SIGUSR1)
}
I have to write a little C program that does the following:
read from stdin
create a child process using fork and encrypt the input with crypt in that child process
use sleep with some random time to simulate the encrypting process and the asynchronous work of the child processes
in my parent process I should catch all the exit-codes of my child processes (using the singal SIGCHLD)
if the user presses Ctrl+C my program should wait for all child processes to finish, then terminate
if the user presses Ctrl+D, I should "ignore" that and read again from stdin
I'm reading from stdin using fgets and I also should catch the EINTR error (I think that's the Ctrl+D "signal"?)
Here is my code so far:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "crypt.h"
#include "signal.h"
#include "errno.h"
#include "sys/wait.h"
char * encryptWord(char* word);
void childTerminated(int sig);
void terminateAllAndExit(int sig);
void nop(int sig);
void readFromStdin();
int childPIDs[1024];
int childProcesses = 0;
int main(int argc, char ** argv) {
readFromStdin();
}
void readFromStdin(void) {
char buffer[1024];
int pid;
while(fgets(buffer, 1024, stdin) != NULL) {
pid = fork();
if(pid == 0) {
signal(SIGINT, nop);
char * encrypted = encryptWord(buffer);
sleep(rand() % 10);
printf("ecnr: %s -> %s\n", buffer, encrypted);
exit(EXIT_SUCCESS);
}
else if(pid > 0) {
signal(SIGCHLD, childTerminated);
signal(SIGINT, terminateAllAndExit);
childPIDs[childProcesses] = pid;
childProcesses++;
}
}
//printf("childProcesses: %d", childProcesses);
}
char * encryptWord(char* word) {
// remove the \n at the end of the input
word[strlen(word)-1] = 0;
word = crypt(word,"sr");
return word;
}
void childTerminated(int sig) {
childProcesses--;
//printf("child terminated.\n");
}
void terminateAllAndExit(int sig) {
//pid_t p;
int status;
//printf("childProcesses: %d\n", childProcesses);
while(childProcesses > 0) {
(void)wait(&status);
if(WEXITSTATUS(status) == EXIT_SUCCESS) {
childProcesses--;
}
}
printf("All child processes terminated. Exiting...\n");
exit(EXIT_SUCCESS);
}
void nop(int sig) {
//signal(SIGINT, nop);
}
The code is working pretty nice now, encrypting works in my child processes and simulating the time they need to encrypt the input.
But, if I press Ctrl+C it's not working how it should. All child processes terminate immediately instead of waiting the time I've set in sleep.
And the last one, how can I catch the EINTR error?
Thank's for your help!
what I want is this:
1 main process that create 4 children process where:
-> The main process receive messages from the children through the queue and print the message recieved.
-> The children send messages (a string with priority+message) through the queue and finish.
All in a while (1), so, when you CTRL+C, the children finish first (the signal is in the children code) and then, the parent finish.
For the moment, I am having problem with mq_send() and mq_recieve().
Well, this is my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
void sigint_handler()
{
/*do something*/
printf("killing process %d\n",getpid());
exit(0);
}
int main ()
{
mqd_t mqd;
struct mq_attr atributos;
// atributos.mq_maxmsg = 10;
//
// atributos.mq_msgsize = 50;
printf ("This is the parent. PID=%d\n",getpid ());
int num_children = 4;
int i;
int pid;
int status;
char buffer [50];
while (1){
for (i=0; i<num_children ;i++){
if ((pid=fork()==0)){
signal(SIGINT, sigint_handler);
int prio = rand () % 3;
printf ("%d\n",prio);
char * msg= "Hi dude";
char * priority=NULL;
if (prio == 0){
priority = "NORMAL";
}
else {
priority = "URGENT";
}
char* toSend=NULL;
toSend = malloc(strlen(msg)+1+strlen(priority));
strcpy (toSend,priority);
strcat (toSend,msg);
printf ("%s\n",toSend);
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
if (mq_send(mqd, msg , strlen(toSend), prio) == -1) {
printf ("Error mq_send\n");
exit (-1);
}
mq_close(mqd);
printf ("This is children %d\n",getpid());
sleep(1);
exit(0);
}
}
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
//Rest Parent code
if (mq_receive(mqd, buffer, strlen(buffer),0)==-1){
printf ("Error mq_recieve\n");
exit(-1);
}
printf("Received: %s\n",buffer);
sleep (1);
waitpid(pid,&status,0);
printf ("This is the parent again %d, children should have finished\n",getpid());
mq_close(mqd);
}
}
I don't know why both mq_send() and mq_receive() returns -1, what am I doing wrong¿?
And you you see something wrong in my code in order to do what I intend apart from the error I am talking about, let me know.
Thank you in advance, I appreciate any help.
user58697 touched upon the biggest problems.
(1) Your queue opens were failing with EINVAL because you wee passing uninitialized attributes because you commented out assignments.
(2) You were opening both queues for write-only. The parent queue needed to be opened in read mode.
(3) Execute permissions don't mean anything to a queue so 777 permissions while not invalid are unnecessary.
(4) Your sends/receives were failing because of invalid lengths. In many if not most cases it is just easier and safer to allocate your buffers to the length attribute of the queue. In this case you know the length before hand but in programs that don't you can get the value via mq_getattr.
(5) You weren't calling srand to seed the RNG before calling rand.
(6) You had a memory leak where you allocate space (unnecessarily) for the message but never freed it.
(7) What you were trying to do with passing priorities is redundant. POSIX MQs have priorities already built in. You can just use those.
I took out some of the fluff (mainly the loops & signals) to concentrate more on the queue aspects of your program.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
int main()
{
srand(time(NULL));
mqd_t mqd;
struct mq_attr atributos = {.mq_maxmsg = 10, .mq_msgsize = 50};
int i;
int pid;
int status;
int num_children = 4;
char buffer[atributos.mq_msgsize];
for (i = 0; i < num_children; i++)
{
if ((pid = fork() == 0))
{
int prio = rand () % 3;
char* msg = "Hi dude";
strncpy (buffer, msg, sizeof(buffer));
if ((mqd = mq_open("/queue.txt", O_CREAT | O_WRONLY, 0666, &atributos)) == -1)
{
perror("child mq_open");
exit(1);
}
if (mq_send(mqd, buffer, sizeof(buffer), prio) == -1)
{
perror("mq_send");
exit(1);
}
mq_close(mqd);
exit(0);
}
}
// parent
if ((mqd = mq_open("/queue.txt", O_CREAT | O_RDONLY, 0666, &atributos)) == -1)
{
perror("parent mq_open");
exit(1);
}
int priority;
for (int i = 0; i < num_children; ++i)
{
if (mq_receive(mqd, buffer, sizeof(buffer), &priority) == -1)
{
perror("mq_recieve");
exit(1);
}
printf("Received (%s): %s\n", (priority == 0) ? "NORMAL" : "URGENT", buffer);
pid_t childpid;
if ((childpid = waitpid(-1, &status, 0)) > 0)
{
if (WIFEXITED(status))
printf("PID %d exited normally. Exit status: %d\n",
childpid, WEXITSTATUS(status));
else
if (WIFSTOPPED(status))
printf("PID %d was stopped by %d\n",
childpid, WSTOPSIG(status));
else
if (WIFSIGNALED(status))
printf("PID %d exited due to signal %d\n.",
childpid,
WTERMSIG(status));
}
}
mq_close(mqd);
}
First and foremost, when a system call fails, print errno (and strerror(errno)).
Now, obvious mistakes:
as was mentioned, you need a read access to be able to mq_receive()
what is strlen(buffer)?
you are passing attributes without initializing them.
To summarize, print errno and see what is wrong.
My server needs to support multiple clients , for the moment let's assume that we're
working with 2 clients .
Here's the server :
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#define FIFONAME "fifo_clientTOserver"
#define SHM_SIZE 1024 /* make it a 1K shared memory segment */
#define ROWS 10
#define COLS 10
void error(char* str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
unlink(FIFONAME); // remove any previous fifo pipes
// create a FIFO named pipe - only if it's not already exists
if(mkfifo(FIFONAME , 0666) < 0)
error("mkfifo");
/**
* process 1
*/
// open the fifo for reading
int server_to_client = open(FIFONAME, O_RDONLY);
int reading;
while (1)
{
if (read(server_to_client, &reading ,sizeof(int)) < 0)
perror("read");
else
break;
}
printf("Reading from the fifo : %d\n" , reading);
if (close(server_to_client) < 0)
error("close");
// casting into pid_t
pid_t pid = (pid_t)reading;
// signal to the process that he's the first
kill(pid, SIGUSR2);
/**
* process 2
*/
printf("Now waiting for process 2...\n");
// doing it again - this time for the second process
// remove any previous fifo pipes
unlink(FIFONAME);
// create a FIFO named pipe - only if it's not already exists
if(mkfifo(FIFONAME , 0666) < 0)
error("mkfifo");
printf("Server tester1\n");
server_to_client = open(FIFONAME, O_RDONLY);
// grab the PID of process 2
while (1)
{
if (read(server_to_client, &reading ,sizeof(int)) > 0)
break; // got the data
}
printf("Server tester2\n");
printf("Reading from the fifo : %d\n" , reading);
if (close(server_to_client) < 0)
error("close");
// casting into pid_t
pid = (pid_t)reading;
// signal to the process that he's the first
kill(pid, SIGUSR2);
return 0;
}
The problem is , that both clients needs to pass their PID (this is not a father-son relation !!! those are two separate processes) , and then the server signals with SIGUSR2 to the first process that he is the first one chosen , and if so , then that process works with a character of type X .
On the other hand ,if you're the second process ,you work with a character of type Y .
Here's the client :
int static flagger = 0;
char process_char = 'a';
/**
* handler for SIGUSR2
*/
void my_handler(int signum)
{
printf("foo bar\n");
if (signum == SIGUSR2)
{
printf("Received SIGUSR2!\n");
flagger++;
}
printf("flagger is :%d\n" , flagger);
if (flagger == 1)
{
// then process works with "X"
process_char = 'x';
printf("I'm process 1, working with X char\n");
// exit(1);
}
else if (flagger == 2)
{
process_char = 'Y';
printf("I'm process 2 , working with Y char\n");
// exit(1);
}
}
void error(char* str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
pid_t pid;
/* get the process id */
if ((pid = getpid()) < 0)
{
perror("unable to get pid");
}
else
{
printf("The process id is %d\n", pid);
}
int pidInt = (int)pid; // convert the pid to int
// write pid into the fifo
int fd = open("fifo_clientTOserver",O_WRONLY); // open the fifo for writing
if(fd < 0)
{
perror("open");
exit(1);
}
signal(SIGUSR2, my_handler);
printf("Tester1\n");
// writing the PID of the client into the pipe
write(fd, &pidInt ,sizeof(int));
close(fd); // closing the pipe
printf("Tester2\n");
while(1)
{
printf("Waiting for the signal...\n");
sleep(1);
}
// more code
}
I tried to use a static int variable in the client (the flagger) to distinguish between the SIGUSR2 signals (either 1st or 2nd) but it doesn't help since , to each client the static flagger is a new variable that starts with 0 and reaches 1 .
How can I distinguish between the 1st time that a process received SIGUSR2 and the second time that another process received SIGUSR2 ?
If you need to pass data around, then signals are not an appropriate mechanism. Consider using a different IPC method, such as named pipes.