Access shared memory to child process with signal - c

I need some help with my c program. Basically, in my c program, I wish my parent process calculates a+b and my child process calculates 3*(a+b). However, I don't how to access the shared memory after sending the signal. Any help is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void sigcont(int shmid);
int main (int argc, char *argv[]){
int shmid;
int *result;
pid_t pid;
int size_data = 2 * sizeof (int);
shmid = shmget (IPC_PRIVATE, size_data, 0666 | IPC_CREAT);
pid = fork ();
if (pid == 0) {
signal(SIGCONT, sigcont);
while (1);
}
else {
sleep(1);
result = (int *) shmat (shmid, NULL, 0);
result[0] = atoi (argv[2]) + atoi (argv[1]);
printf ("Result in parent process %d: %d.\n", getpid() , result[0]);
printf ("Send a SIGCONT to process %d.\n\n", pid);
shmdt (result);
kill (pid, SIGCONT);
wait(NULL);
printf ("\nThis is the End.\n");
}
return 0;
}
void sigcont(int shmid){
printf("Get a SIGCONT.\n");
printf("Result in child process ID: %d.\n", getpid());
exit(0);
}
What I have tried:
Put one parameter in void sigcont(int shmid);
As I am learning from https://www.geeksforgeeks.org/signals-c-set-2/. Do signal() and kill() must use in pair? I get Thus, I tried to pass a value to it. Not working.
Sigstop() and Sigcont()
I tried to avoid using signal() in my child process so that I can access shmid directly. But I couldn't find a lot of examples of Sigstop() and Sigcont(). It fails as well.
It's really hard to get my desired result even it looks simple. Can anyone help with this? Any help is appreciated.

Notes: added error checking; call shmat() and save to global before fork(), child to inherit attached shared mem; SIGCONT better for stopped process, selected SIGUSR1; arg to sig handler is signal #; child was spinning, for minimal overhead better to pause().
This version is an example, and does not attempt to support every system imagined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int *shmloc;
void shandler(int sig)
{
printf("pid %d, sig %d\n", getpid(), sig);
printf("mult result: %d\n", *shmloc * 3);
}
int main(int argc, char *argv[])
{
int a, b, shmid, size_data, sig;
pid_t pid;
if (argc < 3) {
fprintf(stderr, "missing args a b\n");
return (1);
}
// OP: shmget() size arg, some systems may require a minimum, may roundup
size_data = 2 * sizeof (int);
shmid = shmget(IPC_PRIVATE, size_data, 0666 | IPC_CREAT);
if (shmid == -1) {
fprintf(stderr, "shmget failed, %s\n", strerror(errno));
return (1);
}
shmloc = shmat(shmid, NULL, 0);
if (shmloc == (void *) -1) {
fprintf(stderr, "shmat failed, %s\n", strerror(errno));
return (1);
}
sig = SIGUSR1;
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork failed, %s\n", strerror(errno));
return (1);
}
// child only
if (pid == 0) {
signal(sig, shandler);
pause();
printf("child exit\n");
_exit(0);
}
sleep(1);
// OP: care about non-digits in cmd-line args?
a = atoi(argv[1]);
b = atoi(argv[2]);
*shmloc = a + b;
printf("parent pid %d, add (%d, %d) result %d\n", getpid(), a, b, *shmloc);
shmdt(shmloc);
printf("sending signal %d to child %d\n", sig, pid);
kill(pid, sig);
wait(NULL);
printf("\nThis is the End.\n");
return (0);
}

Related

How do find the granchild pid in C?

I am trying to code a toy process manager and was wondering how do I find the grandchild pids when one of my children pids dies. I.e. how to deal with the "Readiness protocol".
systemd has the "Type=forking" option, which as far as I understand, waits for the forked pid to die and then assumes that one of the forked pid's children is the actual "daemon" to monitor.
My code so far is as following, but I am missing the XXX
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/prctl.h>
int
main (int argc, const char *argv[])
{
printf("sup stared\n");
int pid;
prctl(PR_SET_CHILD_SUBREAPER);
pid = fork();
if (pid == 0) {
setpgid(0, 0);
printf("service started, pid: %d, pgid: %d\n",
getpid(), getpgid(0));
int dpid;
dpid = fork();
if (dpid == 0) {
printf("daemon started, pid: %d, pgid: %d\n",
getpid(), getpgid(0));
while (1);
}
printf("service exiting\n");
return 0;
} else {
printf("service pid: %d\n", pid);
int rc;
rc = waitpid(pid, NULL, 0);
printf("service exited? %d\n", rc);
int dpid;
dpid = XXcX();
printf("daemon, %d\n", dpid);
}
return 0;
}

Fork and exec several children in linux

I want to fork and exec several processes from another.
My parent code is
/*Daddy.c*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(void)
{
int status;
char *nChild;
for (int i=0; i<3;i++){
int pid = fork();
if (pid == 0)
{
sprintf(nChild, "%d", i);
printf("%d\n", i);
char *const arguments[]={nChild, NULL};
fflush(NULL);
execv("child",arguments);
printf("\nNo , you can't print!\n");
}else if (pid == -1){
printf("%d\n", getpid());
exit(0);
}
}
wait(&status);
printf("Dad %d went out!\n", getpid());
exit(0);
}
and my child process is
/*child.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int args, char **argv){
if( args !=2){
printf("Child going away!\n");
exit(1);
}
printf("Child %s: %d going away stylishly!\n", argv[1], getpid());
exit(0);
}
When I don´t create three forks, but one, I know how to create the child, do some work and exit from child and parent. But, in this case, with several children it seems like the child never executes.
Because of the line wait(&status) I did hope that when the first child exits, the parent also exits but, any child prints any message.
Some relevant previous questions didn´t help.
You need to make parent wait for all child processes to finish. If not, assume that 1 child waited for is done and then parent exits. What about the other 2 children? They become orphan since their parent doesn't wait for them.
pid_t wpid;
int status = 0;
.
.
while ((wpid = wait(&status)) > 0); // the parent waits for all the child processes
This code did the job
/* daddy.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
int status=0;
char nChild[16];
pid_t wpid;
for (int i=0; i<3;i++){
sprintf(nChild, "%d", i);
int pid = fork();
if (pid == 0)
{
printf("%s\n", nChild);
char *const arguments[]={"child", nChild, NULL};
fflush(NULL);
execv("child",arguments);
printf("\nNo , you can't print!\n");
}else if (pid == -1){
printf("%d\n", getpid());
exit(0);
}
}
while ((wpid=wait(&status)) >0);
printf("Dad %d went out!\n", getpid());
exit(0);
}
As #OnzOg said in the comments of the question, allocation of nChild was the main problem. Also execv need pass child name twice, one as argument.
And finally, to improve the code, parent process needs to wait all processes to finish.

Pipe creation through functions

I was wondering if someone can help me modify my current code....
Currently it creates my process using fork() and takes a pointer to a function which executes that childs code block.
I wanted to play around with pipes and attempt to now have Process Y send its pid to Process X and then i want to send it back to the Main...
Heres what i have currently
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h> // exit
#include <fcntl.h>
#include <sys/wait.h>
void processX();
void processY();
pid_t addChild(void (*childPtr) (), int fileDes[2]) {
pid_t cpid;
if((cpid=fork()) == 0) {
pipe(fileDes);
childPtr(fileDes);
wait(NULL);
exit(0);
} else if (cpid < 0) {
printf("failed to fork");
exit(1);
} else {
}
return cpid;
}
void processY(int fileDes[2]) {
printf("Child Y[%d] Created of Parent X[%d]\n", getpid(), getppid());
printf("We are now going to write Y PID to process X\n");
pid_t a = getpid();
char buf[1024]; // child reads from pipe() to buffer
close(fileDes[0]); // close reading end of the pipe
write(fileDes[1], &a, sizeof(buf) / sizeof(int));
}
void processX(int fileDes[2]) {
printf("Child X[%d] Created of parent Main[%d]\n", getpid(), getppid());
int status;
pid_t Y = addChild(processY, fileDes);
wait(&status);
pid_t new_val = 5;
close(fileDes[1]); // closing the writing end of the pipe.
read(fileDes[0], &new_val, sizeof(new_val));
printf("Message read with number %d: \n", new_val);
}
int main() {
int status;
int fd[2];
printf("Main process[%d]\n", getpid());
pid_t root = addChild(processX, fd);
wait(&status);
printf("We are going to read from X to Main and then return the Value we got from Y\n");
return 0;
}
I dont know to create a pipe from Y - X and then X - Main....
Y---->send pid ----> X received Y pid ----- send new info to main --->Main print received data...
My answer i came up with
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h> // exit
#include <fcntl.h>
#include <sys/wait.h>
void processX();
void processY();
pid_t addChild(void (*childPtr) (), int fileDes[2], int backToMainFd[2]) {
pid_t cpid;
if(childPtr != *processX //prevents the the pipe from main to x from recreating
pipe(fileDes);
if((cpid=fork()) == 0) {
if(childPtr == *processX) {
childPtr(fileDes, backToMainFd);
} else {
childPtr(fileDes);
}
wait(NULL);
exit(0);
} else if (cpid < 0) {
printf("failed to fork");
exit(1);
} else {
}
return cpid;
}
void processY(int fileDes[2]) {
printf("[PROCESS Y]: Child Y[%d] Created of Parent X[%d]\n", getpid(), getppid());
pid_t a = getpid();
char buf[1024]; // child reads from pipe() to buffer
close(fileDes[0]); // close reading end of the pipe
write(fileDes[1], &a, sizeof(buf) / sizeof(int));
}
void processX(int fileDes[2], int BackToMainFd[2]) {
printf("[PROCESS X]: Child X[%d] Created of parent Main[%d]\n", getpid(), getppid());
int status;
pid_t Y = addChild(processY, fileDes, NULL);
wait(&status);
pid_t new_val = 5;
close(fileDes[1]); // closing the writing end of the pipe.
read(fileDes[0], &new_val, sizeof(new_val));
printf("[PROCESS X]: We got Ys' PID as:%d from [PROCESS Y]\n", new_val);
close(BackToMainFd[0]); // close reading end of the pipe
char buf[1024]; // child reads from pipe() to buffer
write(BackToMainFd[1], &new_val, sizeof(buf) / sizeof(pid_t));
}
int main() {
int status;
int fd[2];
int backToMainFD[2];
printf("Main process[%d]\n", getpid());
pipe(backToMainFD);
pid_t root = addChild(processX, fd, backToMainFD);
wait(&status);
pid_t new_val = 5;
close(backToMainFD[1]); // closing the writing end of the pipe.
read(backToMainFD[0], &new_val, sizeof(new_val));
printf("[MAIN]: We got Ys' PID as:%d from [PROCESS X]\n", new_val);
printf("Send sig kills too Y and root\n");
kill(new_val, SIGKILL);
kill(root, SIGKILL);
printf("Terminate program.\n");
return 0;
}

how can I send a signal between a child and a parent processes in linux

I have two cods the first one is for the parent which sends a signal (SIGUSER1) to the child and when the child receive it he should print that he received it.
Parent code
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
void sighand(int);
int main()
{
int cpid, ppid;
ppid = getpid();
printf("My process ID is %d\n", ppid);
FILE *fp1;
fp1 = fopen("cpid.txt", "w+");
cpid = fork();
if ( cpid == 0 ) {
printf("I am the child => PID = %d\n", getpid());
}
else
printf("I am the parent => PID = %d, child ID = %d\n", getpid(), cpid);
fprintf(fp1, "%d\n", cpid);
// kill(cpid, SIGUSR1);//id, signal, send
sigset(SIGUSR2, sighand);
return 0;
}
void sighand(int the_sig){
if (the_sig == SIGUSR2){
printf("sigusr2 received");
exit(1);
}
}
Child code
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
void sighand1(int);
int main()
{
FILE *fp1;
int pid;
fp1 = fopen("cpid.txt", "r");
fscanf(fp1, "%d,", &pid);
sigset(SIGUSR1,sighand1);
while(1) {
printf("Waiting..");
sigpause(SIGUSR1);
}
return 0;
}
void sighand1(int the_sig)
{
if (the_sig == SIGUSR1){
printf("sigusr1 received");
exit(1);
}
}
When I start the code it prints that the process (child) was created then when I send a signal it wont do any thing the child stuck in a loop or the wait and the parent wont do anything can any one tell me where did i go wrong in my code or logic.
Your code has several problems:
You try to pass some pid through a file, but you can use the getppid() function (get parent id)
You have some child code, but it is not called
no signal is launched
So your code can be corrected this way:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
void parent_handler(int the_sig)
{
if (the_sig == SIGUSR2){
printf("sigusr2 received in parent\n");
}
}
void child_handler(int the_sig)
{
if (the_sig == SIGUSR1){
printf("sigusr1 received in child\n");
kill(getppid(), SIGUSR2);
exit(1);
}
}
int child_function()
{
/* prepare to receive signal */
sigset(SIGUSR1,child_handler);
while(1) {
printf("Waiting..");
fflush(stdout);
/* wait for signal */
sigpause(SIGUSR1);
}
return 0;
}
int main()
{
int cpid, ppid;
ppid = getpid();
printf("My process ID is %d\n", ppid);
cpid = fork();
if ( cpid == 0 ) {
printf("I am the child => PID = %d\n", getpid());
child_function();
return 0;
}
else
printf("I am the parent => PID = %d, child ID = %d\n", getpid(), cpid);
/* child will never reach this point */
sleep(1);
/* prepare parent to received signal */
sigset(SIGUSR2, parent_handler);
/* send signal to child */
kill(cpid, SIGUSR1);
sleep(1);
return 0;
}

Fork() and Posix Queues. Send and Receive strings

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.

Resources