Hello I Have problem with getting signal in my second program.
I have code like this:
Program1:
int main() {
int id = fork();
if (id == 0) {
execl("program2", "program2", NULL);
kill(id, SIGUSR1);
}
return 0;
}
Program 2:
void signal_handler1(int sig) {
printf("test\n");
}
int main(int argc, char* argv[]) {
signal(SIGUSR1, signal_handler1);
printf("Hello world\n");
return 0;
}
And why I get
Hello World
Instend of
test
Hello World
execl() return only if an error occured, so kill() is never executed in program1 if execl() succeed. It should send signal in parent process. But signal may be sent before program2 setup signal handler, so signal may be ignored. Let it wait some time before sending signal:
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
pid_t id = fork();
if (id == -1) {
perror("fork");
return 1;
}
if (id == 0)
{ /* Child process */
/* Execute program from current directory */
execl("program2", "program2", NULL);
perror("execl");
} else
{ /* Parent process */
/* Wait while child setup signal handler */
sleep(1);
if (kill(id, SIGUSR1) == -1)
{
perror("kill");
}
}
return 0;
}
If you want program2 to catch signal, let it wait for signal:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
static sig_atomic_t sigusr1_received = 0;
static void signal_handler(int)
{
sigusr1_received = 1;
}
int main(void)
{
signal(SIGUSR1, signal_handler);
printf("Hello World!\n");
while (1)
{
/* Check flag first to avoid race condition */
if (sigusr1_received)
{
printf("test\n");
/* Exit after receiving signal */
break;
}
pause(); /* Wait for any signal */
}
return 0;
}
Look to your parent code:
int main()
{
int id = fork();
if (id == 0) {
you don't test for negative id (indicating some error from fork()) but, as this error is rare, it's not a problem here)
you have tested if id is zero (just above), so think twice, are you killing process with process id 0??? Shouldn't this kill be in some other part of the code?
execl() only returns if it indeed fails. You should only print some error about why execl() failed and exit() with a return code indicating that.
execl("program2", "program2", NULL);
fprintf(stderr, "EXECL: %s\n", strerror(errno));
exit(EXIT_FAILURE);
/* kill(id, SIGUSR1); <-- this code will never execute */
}
return 0;
}
Exec functions are never expected to return, as the program that executes them is overwritten by the program you are attempting to execute. So, if you call execl(2), don't put anything but error code below it. It's not like calling a subroutine, that returns to the calling program. It never returns (well, as said, only if the function fails).
If you want to send a signal to your child, the kill() call should be after the if sentence (where, indeed, is the parent code to execute) You should check first for -1, as this means that fork() failed.
So a better sample code would be: (I have put, not as you did, a complete example, ready to be built and executed at your site, please read How to create a minimal, reproducible example and follow the guidelines there to post testable code. (you lack header files and many things for this code to be testable out of the box)
program1.c
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include "log.h" /* see log.h file, below */
char *p1;
int pid;
int main(int argc, char **argv)
{
int res;
p1 = argv[0];
char *p2 = argc > 1 ? argv[1] : p1;
pid = getpid();
LOG(p1, pid, "STARTING\n");
LOG(p1, pid, "IGNORING SIGUSR1(%d)\n", SIGUSR1);
signal(SIGUSR1, SIG_IGN);
int id = fork();
if (id < 0) { /* error */
ERR(p1, pid, "FORK: %s\n", strerror(errno));
}
if (id == 0) { /* child process */
pid = getpid(); /* a new pid as we are children */
if (argc <= 1) {
ERR(p1, pid, "nothing to execute\n");
}
/* shift the parameters to get the next command name
* and parameter list */
argv++;
argc--;
LOG(p1, pid, "about to EXECV(");
char *sep = "";
for (int i = 0; i < argc; i++) {
LOG_TAIL("%s\"%s\"", sep, argv[i]);
sep = ", ";
}
LOG_TAIL(").\n");
/* we use execv(2) instead of execl(2) because
* we are using the parameters as derived from
* our own parameters, so we change (we did
* above) the local parameters to main to get
* the parameter list to execv(). */
execv(p2, argv);
ERR(p1, pid, "EXEC: %s\n", strerror(errno));
}
/* id > 0 */
LOG(p1, pid, "FORKed a new child (pid=%d)\n", id);
{ /* randomize, as all children start at the same time
* calling srandom() with a time based value will not
* be a good chance, so I selected to read the seed
* value from /dev/random */
static const char rand_dev[] = "/dev/random";
int fd = open(rand_dev, O_RDONLY);
int val;
if (fd >= 0) {
read(fd, &val, sizeof val);
srandom(val);
close(fd);
} else {
ERR(p1, pid, "%s: %s\n", rand_dev, strerror(errno));
}
}
int secs = random() % 10 + 1; /* 1..10 s. delay */
LOG(p1, pid, "Waiting for %ds to next step\n", secs);
sleep(secs); /* wait between 1 and 10s. */
LOG(p1, pid, "Sending SIGUSR1(%d) to %s[pid=%d]\n",
SIGUSR1, p2, id);
res = kill(id, SIGUSR1);
if (res < 0) {
LOG(p1, pid, "KILL(%d, SIGUSR1): %s\n", id, strerror(errno));
}
LOG(p1, pid, "Waiting for %s[pid=%d] to finalize\n", p2, id);
int status;
res = wait(&status); /* wait for child to end */
if (res < 0) {
/* error in wait(2) */
ERR(p1, pid, "WAIT: %s\n",
strerror(errno));
} else if (WIFEXITED(status)) {
/* child called exit(2) */
LOG(p1, pid, "WAIT: %s[pid=%d] terminated with exit code %d.\n",
p2, id, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
/* child was aborted by a signal */
LOG(p1, pid, "WAIT: %s[pid=%d] terminated by signal %d%s.\n",
p2, id, WTERMSIG(status),
WCOREDUMP(status)
? ", and dumped a core file"
: "");
}
LOG(p1, pid, "finalizing\n");
exit(EXIT_SUCCESS);
} /* main */
program2.c
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "log.h"
char *pn;
int pid;
void signal_handler1(int sig) {
LOG(pn, pid, "RECEIVED signal %d\n", sig);
}
int main(int argc, char* argv[]) {
pn = argv[0];
pid = getpid();
LOG(pn, pid, "STARTING\n");
LOG(pn, pid, "Installing signal handler for SIGUSR1(%d)\n",
SIGUSR1);
signal(SIGUSR1, signal_handler1);
LOG(pn, pid, "Program params: ");
char *sep = "";
for (int i = 1; i < argc; i++) {
LOG_TAIL("%s[%s]", sep, argv[i]);
sep = ", ";
}
LOG_TAIL("\n");
if (argc > 1) { /* at least one parameter, so pause */
LOG(pn, pid, "Waiting to receive a signal\n");
int res = pause();
if (res < 0) {
LOG(pn, pid, "PAUSE: %s\n", strerror(errno));
}
}
/* and print final message */
LOG(pn, pid, "Hello world, program terminating\n");
return 0;
}
Both programs need:
log.h
#ifndef _LOG_H
#define _LOG_H
#define F(_prog, _pid, _fmt) "%s:%s:%d:pid=\033[1;%dm%d\033[m:%s: "\
_fmt, _prog, __FILE__, __LINE__, (_pid % 7 + 31), (_pid), __func__
#define LOG_TAIL(_fmt, ...) \
printf(_fmt, ##__VA_ARGS__)
#define LOG(_prog, _pid, _fmt, ...) \
printf(F(_prog, _pid, " "_fmt), \
##__VA_ARGS__)
#define ERR(_prog, _pid, _fmt, ...) do { \
printf(F(_prog, _pid, "ERROR: "_fmt), \
##__VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#endif /* _LOG_H */
and you can build with:
Makefile
targets = p1 p2
toclean = $(targets)
p1_objs = program1.o
p2_objs = program2.o
toclean += $(p1_objs) $(p2_objs)
all: $(targets)
clean:
rm -f $(toclean)
p1: $(p1_objs)
$(CC) $(CFLAGS) $(LDFLAGS) $($#_objs) -o $#
p2: $(p2_objs)
$(CC) $(CFLAGS) $(LDFLAGS) $($#_objs) -o $#
program1.o program2.o: log.h
for a run as:
$ p1 p1 p2
p1:program1.c:24:pid=11089:main: STARTING
p1:program1.c:25:pid=11089:main: IGNORING SIGUSR1(10)
p1:program1.c:62:pid=11089:main: FORKed a new child (pid=11090)
p1:program1.c:83:pid=11089:main: Waiting for 1s to next step
p1:program1.c:45:pid=11090:main: about to EXECV("p1", "p2").
p1:program1.c:24:pid=11090:main: STARTING
p1:program1.c:25:pid=11090:main: IGNORING SIGUSR1(10)
p1:program1.c:62:pid=11090:main: FORKed a new child (pid=11091)
p1:program1.c:83:pid=11090:main: Waiting for 6s to next step
p1:program1.c:45:pid=11091:main: about to EXECV("p2").
p2:program2.c:23:pid=11091:main: STARTING
p2:program2.c:25:pid=11091:main: Installing signal handler for SIGUSR1(10)
p2:program2.c:29:pid=11091:main: Program params:
p2:program2.c:46:pid=11091:main: Hello world, program terminating
p1:program1.c:86:pid=11089:main: Sending SIGUSR1(10) to p1[pid=11090]
p1:program1.c:92:pid=11089:main: Waiting for p1[pid=11090] to finalize
p1:program1.c:86:pid=11090:main: Sending SIGUSR1(10) to p2[pid=11091]
p1:program1.c:92:pid=11090:main: Waiting for p2[pid=11091] to finalize
p1:program1.c:101:pid=11090:main: WAIT: p2[pid=11091] terminated with exit code 0.
p1:program1.c:111:pid=11090:main: finalizing
p1:program1.c:101:pid=11089:main: WAIT: p1[pid=11090] terminated with exit code 0.
p1:program1.c:111:pid=11089:main: finalizing
$ _
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;
Hi I'm just working on signalling between two processes. I have a main process (eg. MAIN) which keeps on running. This MAIN is forked from a Wrapper process (eg. WRAP).
Here is my code which will actually launch the WRAP process, which in turn will create a child process as MAIN.
When certain initialization is completed in MAIN I would like to post a signal SIGUSR1, which will be captured by WRAP and does some other stuffs.
The problem with my code is when the signal is raised from MAIN it is never trapped by WRAP process. Pls. share your suggestions on this code or if there are any other ways to achieve this.
Thank you.
In MAIN process:
After Init is completed I have added this code,
main()
{
// Do some work here
int pid = GetProcessID(); // Returns the process ID of WRAP process
kill(pid,SIGUSR1); // Tries to send signal to WRAP process
// Other code
}
int GetProcessID()
{
int pid = 0;
char results[128];
FILE *fp = popen("pgrep WRAP", "r");
if(fp == NULL)
{
printf("Error: Failed to get Process ID");
}
else
{
while(fgets(results, 128, fp) != NULL)
{
pid = atoi(results);
}
pclose(fp);
}
return pid;
}
In WRAP process:
main()
{
int pid;
signal(SIGUSR1,InitComplete);
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if (pid == 0)
{
/* child */
system("mainProc.out");
}
else
{
/* parent */
if(KeepListening() == 1)
printf("Init completed successfully\n");
}
return 0;
}
int KeepListening()
{
const int MAX_WAIT_TIME = 180;
int procStarted = 0;
int res = 0;
sigset_t origset;
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGWINCH);
sigaddset(&ss, SIGUSR1);
res = sigprocmask(SIG_BLOCK, &ss, &origset);
if(res)
{
printf("\nError: sigprocmask returned an error\n");
}
struct timespec theTimeout;
theTimeout.tv_nsec = 0;
theTimeout.tv_sec = MAX_WAIT_TIME;
int sig = 0;
siginfo_t theInfo;
memset(&theInfo, '\0', sizeof(theInfo));
int timedwaitcount = 0;
do
{
sig = sigtimedwait(&ss, &theInfo, &theTimeout);
if(sig < 0)
{
if(EAGAIN == errno)
{
timedwaitcount++;
}
else
{
PrintMessage("Error:Error occured with sigtimedwait\n");
}
}
else
{
timedwaitcount = 0;
}
if(SIGUSR1 == sig)
{
return 1;
}
}while(SIGWINCH == sig || 0 == sig);
return procStarted;
}
void InitComplete()
printf("InitComplete in MAIN. Signal Received.\n");
}
I prepared a short sample which demonstrates how it should work.
Source file test-exec.c for what you call WRAPPER:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
static int sigUsr1Rcvd = 0;
enum { SleepTimeUS = 50000 /* us */ };
void onSigUsr1(int sig)
{
if (sig == SIGUSR1) sigUsr1Rcvd = 1;
}
int main(int argc, char **argv)
{
int pid; char buffer[20]; int status = 0;
/* report alive */
printf("%s started...\n", argv[0]);
/* install signal handler before fork() */
signal(SIGUSR1, &onSigUsr1);
/* fork child */
if (pid = fork()) { /* main process */
if (pid < 0) {
perror("ERROR in fork()");
return -1;
}
} else { /* child process */
if (execl("./test-exec-child", "test-exec-child", NULL)) {
perror("ERROR in execl()");
return -1;
}
return 0;
}
/* main process */
/* waiting for SIGUSR1 */
while (!sigUsr1Rcvd) usleep(SleepTimeUS);
printf("%s: Child inited.\n", argv[0]);
/* wait for termination of child */
wait(&status);
/* done */
printf("%s exiting...\n", argv[0]);
return 0;
}
Source code file test-exec-child.c for what you call MAIN:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
enum { SleepTimeS = 3 /* s */ };
int main(int argc, char **argv)
{
char buffer[20];
/* report alive */
printf("%s started...\n", argv[0]);
/* consume some time */
printf("%s: initializing...\n", argv[0]);
sleep(SleepTimeS);
printf("%s: done.\n", argv[0]);
/* send signal to parent */
kill(getppid(), SIGUSR1);
/* spend time until user feed-back */
printf("Press [ENTER] to continue...");
fgets(buffer, sizeof buffer, stdin);
/* done */
printf("%s exiting...\n", argv[0]);
return 0;
}
I compiled and tested this with gcc on cygwin:
$ gcc -o test-exec test-exec.c
$ gcc -o test-exec-child test-exec-child.c
$ ./test-exec
./test-exec started...
test-exec-child started...
test-exec-child: initializing...
...
test-exec-child: done.
./test-exec: Child inited.
Press [ENTER] to continue...
[ENTER]
test-exec-child exiting...
./test-exec exiting...
$
I'm implementing a function which receives a parsed-to-array command lines ("./waiter 20 &" will be parsed, and the function will receive the array
{"./waiter","20","&"} for example).
If the last argument is &, the process should run in the background.
To prevent zombies, I need to use a new thread that will wait for the child process.
The attached code is my working program, and all my efforts to add a new thread that will wait for the child process failed.
Anyone can guide me?
Attaching the code, with some of the leftovers of my unsuccessful tries.
(the function is process_arglist)
update: after a lot of tries using what suggested here, its still failing and im not sure why. updated code attached.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
void func(void* ptr) {
pid_t* mypid = (pid_t*)ptr;
waitpid(*mypid);
pthread_detach(pthread_self());
}
int process_arglist(int count, char** arglist){
int isBackground = 0;
pid_t pid;
int status;
char** parsedList;
if (strcmp(arglist[count-1],"&") == 0) {
printf("###we are in the & situation\n");
parsedList = (char**)malloc((count-1)*sizeof(char*));
if (parsedList == NULL) {
printf( "Error: malloc failed - %s\n", strerror(errno));
}
int i;
for (i=0;i<count-1;i++){
parsedList[i] = arglist[i];
}
/*printf("parsed list:\n");
for (i=0;i<count-1;i++) {
printf(" %d: %s\n", i,parsedList[i]);
}*/
if ((pid = fork()) < 0) { /* fork a child process */
printf( "Error: fork failed");
exit(0);
} else if (pid == 0) { /* for the child process: */
if (execvp(*parsedList,parsedList) < 0) { /* execute the command */
printf( "Error: execvp failed - %s\n", strerror(errno));
exit(0);
}
} else {
pthread_t thread;
pthread_create(&thread, NULL, (void*) &func, (void*) &pid);
}
} else {
if ((pid = fork()) < 0) { /* fork a child process */
printf( "Error: forking child process failed - %s\n", strerror(errno));
exit(0);
}
else if (pid == 0) { /* for the child process: */
if (execvp(*arglist,arglist) < 0) { /* execute the command */
printf( "Error: execvp failed - %s\n", strerror(errno));
exit(0);
}
}
else { /* for the parent: */
while (waitpid(&status) != pid); /* wait for completion */
}
}
}
First, switch from calling wait to calling waitpid. Otherwise, if you have more than one thread waiting, they'll steal each other's notifications.
Second, break the call to waitpid into its own function that takes the PID to wait for as a parameter. Cast it through void *, since that's what's used for thread parameters.
Third, change the call to the function to a call to pthread_create, casting the PID to wait for to a void * to pass to the newly-created thread.
Lastly, have the thread detach itself, since there won't be anything waiting for the thread to terminate.
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.