I don't know if I'm asking the right question, but after several hours of searching, I can't find my answer. So I explain what I need.
I would like to create a child process with fork and that child process will wait until it receives a signal or changes a variable value. I mean I don't want to be creating a process every time I need it, I want it to wait and run when I tell it to, as many times as it needs to.
I have tried several things, but they have not worked, I put the code, I really do not know what to look for to do what I need without thread, or is it only possible to do it with thread?
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
volatile sig_atomic_t runChild = 0;
static void handler(int signum, siginfo_t *sinfo, void *unused){
if (signum == SIGUSR1) {
printf("SIGUSR1 received\n");
runChild = 1;
}
}
int main(int argc, char *argv[]) {
char *newArgv[] = {"myecho", "hello", "world", NULL};
char *newEnviron[] = { "MY_NAME=jcarlosweb", NULL };
struct sigaction sa;
sa.sa_flags =0;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handler;
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("sigaction");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) {
while (!runChild) {
usleep(200);
}
runChild = 0;
execve("./process-pipe-fork/execve/myecho", newArgv, newEnviron);
/* The execve function returns only if an error occurs. */
perror("An error occurred in execve");
abort();
}
// continue execution of parent process without waiting for child process to finish
waitpid(-1, NULL, WNOHANG);
printf("Run myecho:\n");
kill(pid,SIGUSR1);
sleep(3);
printf("Run myecho:\n");
kill(pid,SIGUSR1);
printf("Done\n");
exit(EXIT_SUCCESS);
}
The execve of my myecho program only runs once, and I would like to run it when I say so throughout the main program.
In this case I'm using the exec in the child process, but I could have just put a function that prints a message, for example. The idea I am looking for is the same
Block on a pipe. This might look something like...
#include <err.h>
#include <errno.h>
#include <unistd.h>
int main(void) {
char ch;
int fd[2];
pid_t pid;
ssize_t ret;
pipe(fd); /* to block on */
pid = fork();
if (pid < 0) {
err(1, "fork failed");
} else if (pid == 0) { /* child */
close(fd[1]);
warnx("child %d start", getpid());
/* block until parent goes away */
ret = read(fd[0], &ch, 1);
warnx("child %d is go", getpid());
close(fd[0]);
/* child now does things here ... */
} else { /* parent */
sleep(3);
close(fd[0]);
close(fd[1]);
/* parent does more things here ... */
}
return 0;
}
You cannot wait on a child process for a variable change because the parent process and the child are different processes, and so, they have each their own virtual address space (with no intersections)
There are several ways to do what you want. One has been suggested in another answer, so I will not extend on it, as it looks fine to me.
You can create a thread. A thread runs in a separate stack (separate from main thread) but the whole virtual address space is the same. Both running threads (main and the one you create) share the same addresses and so, one can modify a variable and the other can be looking at it for a change. This solution is feasible, but not very efficient, as while the waiting process is waiting for the variable to change (the variable needs to be defined as volatile, so the compiler doesn't cache the value anywhere and the true value is the one the other thread stores in it) it is consuming cpu making your resources wasted for no reason.
You can use (in a different process) a semaphore, (man semop) for the parent process to change it.
You can use shared memory between processes (see man shmop or man mmap) and so, only the memory corresopnding to the shared memory segment is shared between both processes.
You can use a socket. A socket is a bidirectional communication channel between parent and child, and so it allows you to use a complex protocol to do the most variable communication messages between both processes. You can use reliable unix sockets for this (they are fast, reliable, but require both processes to be in the same machine) or network sockets (the API is the same, which gives you a versatile approach that you can later change in case your needs change)
I recommend you to read:
pthread_create(3) and similar manual pages. A reference of threads.
pthread_mutex(3) and similar manual pages. A reference to synchronization between threads.
semop(2) and friends. Reference to sysv5 semaphores.
mmap(2) and friends. Reference to shared memory segments.
pipe(2) and fifo related documentation. This will show you how a pipe can be used, as it blocks readers and writers when the internal buffer it has is full/empty. This can be a good starting point.
The following code fork()s a child and then it feeds its child with all its own input, while the parent is writing to standard output its own input, it also feeds to the child its input, so the child will work on it and write to a file output.txt:
###pru.c
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int fd[2];
/* we need to get the pipe before fork() so we have it in both,
* parent and child. */
int res = pipe(fd);
if (res < 0) {
perror("pipe");
exit(1);
}
int child_pid = fork();
if (child_pid < 0) {
perror("fork");
exit(1);
}
/* both processes get here. */
if (child_pid == 0) { /* we are the child only */
close(fd[1]); /* we are not using the writing end */
FILE *out = fopen("output.txt", "a+");
FILE *f = fdopen(fd[0], "r");
int c;
while ((c = fgetc(f)) != EOF) {
/* print an hex representation of char */
fprintf(out, "<%02x>", c);
}
/* let's close both */
fclose(out); fclose(f);
/* remember the child gets 0 from fork, so it needs to
* call getpid() syscall to get its pid. */
printf("Child (pid=%d) exiting.\n", getpid());
exit(0);
/* NOTREACHED */
} else {
close(fd[0]); /* we don't use the reading end */
/* we are writing on the writing side of the pipe */
FILE *out = fdopen(fd[1], "w");
int c;
while ((c = fgetc(stdin)) != EOF) {
/* make a copy for the child */
fputc(c, out);
/* and write to stdout */
fputc(c, stdout);
}
fclose(out); /* signal the child that there's no more output */
fprintf(stderr,
"Waiting for the child (whose pid should be %d)"
" to finish\n",
child_pid);
int status;
pid_t exited_pid = wait(&status);
if (exited_pid < 0) {
perror("wait");
exit(1);
}
fprintf(stderr,
"%d exited with status %d\n",
exited_pid, status);
exit(0);
/* NOTREACHED */
} /* else */
} /* main */
whose output is:
$ echo "Hello, world" | ./a.out
Hello, world
Waiting for the child (whose pid should be 2833) to finish
Child (pid=2833) exiting.
2833 exited with status 0
$ _
and the contents of output.txt:
$ cat output.txt
<48><65><6c><6c><6f><2c><20><77><6f><72><6c><64><0a>$ _
I suppose your complaint is that myecho runs after the first kill(pid, SIGUSR1) but not the second time? But as you said yourself, execve doesn't return if it succeeds!
Upon successful execve the child process is no longer running your program at all, it's running the myecho program, which doesn't handle signals, and when myecho calls _exit() the process exits. So by the time the parent calls kill(pid, SIGUSR1) the second time, your child process is a zombie. The second kill won't fail, but it also won't have any effect; a zombie can't respond to signals.
If you want the child to stick around and keep responding to signals, then the child cannot call execve itself to run myecho. Instead, each time the signal is received, the child must fork again, creating a grandchild process to do the exec. The original child doesn't call execve but just returns to its sleep loop to wait for another signal.
As a side remark, I think you've misunderstood the role of waitpid. Your waitpid(-1, NULL, WNOHANG); effectively does nothing at all. It would be used to test whether the child had already exited and reap it if so, immediately returning 0 if yes and -1 if no, but you ignore the return value. You don't need any system call for the parent and child to run independently; that's what happens by default when you fork. You call waitpid or one of its relatives when you want the parent to wait instead of going on running. I think you may have misunderstood something in the documentation.
Which raises the question of who is going to clean up all those zombies. They will stay around and pollute the process table until their parent calls waitpid. You could have the child process, on every wakeup, call waitpid(WNOHANG) in a loop until it returns -1 to reap all grandchildren that have exited. Or you could use a SIGCHLD handler. Likewise, the parent should really be arranging somehow for the child to terminate before the parent does (kill it with another signal, for instance), and then the parent should waitpid for the child, without WNOHANG, before it itself exits.
Finally, instead of usleep in a loop, the preferred way to wait for a signal is with sigwait(). In that case you don't actually need the runChild flag. You still have to install a signal handler for SIGUSR1 but it can just do nothing.
I can try to come back later and post a fixed version of your program as an example.
Thanks to the answers of Nate Eldredge and Luis Colorado I have been able to create 3 examples. I'm going to post them in case it helps other people, I've really done this as an exercise to learn C, but these the examples are nothing without the help of Nate Eldredge and Luis Colorado. I also did another example with sigwait, but I've seen that with Semaphore it's simpler.
1 - Posix Semaphore:
struct sigaction sa; // signal
short int *runChildProcess; // mmap shared memory
sem_t *sem; // semaphore
static void handleChildTerm(int signum, siginfo_t *sinfo, void *unused) {
printf("Child %d exited\n", (int)sinfo->si_pid);
}
static void runChild(pid_t pid) {
if (sem_post(sem) == -1) {
perror("sem_post run child");
exit(EXIT_FAILURE);
}
// When SIGCHLD is caught, sleep(3) is interrupted
// https://stackoverflow.com/questions/14266485/understanding-sigchld-when-the-child-process-terminates
unsigned short int sleepTime = 3;
while ((sleepTime = sleep(sleepTime)) > 0)
;
}
static void termChild(pid_t pid) {
*runChildProcess = 0; // set to 0 to exit the loop
runChild(pid);
if(munmap(runChildProcess, sizeof *runChildProcess) == -1) {
perror("Munmap");
exit(EXIT_FAILURE);
}
if (sem_destroy(sem) == -1) {
perror("sem_destroy");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[]) {
setbuf(stdout, NULL); // make stdout unbuffered
// mmap: memory mapping file, shared with child process with the flag MAP_ANONYMOUS | MAP_SHARED
runChildProcess = mmap(NULL, sizeof *runChildProcess, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
if (runChildProcess == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
*runChildProcess = 1;
// semaphore
sem = mmap(0, sizeof(*sem), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (sem_init(sem, 1 /*shared*/, 0 /*init val*/) == -1) {
perror("sem_init");
exit(EXIT_FAILURE);
}
// signal handler for SIGCHLD (exit child process)
sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NOCLDWAIT;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handleChildTerm;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction SIGCHLD");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) { // child process
while (*runChildProcess) {
sem_wait(sem);
if (*runChildProcess == 0) {
break;
}
printf("Child process started: %d\n", getpid());
}
_exit(EXIT_SUCCESS);
}
printf("Parent process: %d\n", getpid());
runChild(pid);
runChild(pid);
runChild(pid);
termChild(pid);
printf("Done\n");
exit(EXIT_SUCCESS);
}
2 - Pipes
#include <errno.h> // for errno
#include <signal.h> // sigaction
#include <stdbool.h> // bool
#include <stdio.h> // printf
#include <stdlib.h> // exit
#include <string.h> // strlen
#include <sys/mman.h> // mmap
#include <sys/types.h> // pid_t
#include <unistd.h> // fork
bool *runChildProcess; // mmap shared memory
int fd[2]; // pipe
static void runTermChildHandler(int signum, siginfo_t *sinfo, void *unused) {
*runChildProcess = 0;
}
static void termChildHandler(int signum, siginfo_t *sinfo, void *unused) {
printf("Child %d exited\n", (int)sinfo->si_pid);
}
static void runChild(int pipeFd, char *buffer) {
if (write(pipeFd, buffer, strlen(buffer) + 1) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
// When SIGCHLD is caught, sleep(3) is interrupted
// https://stackoverflow.com/questions/14266485/understanding-sigchld-when-the-child-process-terminates
unsigned short int sleepTime = 3;
while ((sleepTime = sleep(sleepTime)) > 0)
;
}
static void termChild(pid_t pid, int pipeFd) {
kill(pid, SIGUSR1);
close(pipeFd);
unsigned short int sleepTime = 1;
while ((sleepTime = sleep(sleepTime)) > 0);
munmap(runChildProcess, sizeof *runChildProcess);
}
int main(int argc, char *argv[]) {
setbuf(stdout, NULL); // make stdout unbuffered
// mmap: memory mapping file, shared with child process with the flag MAP_ANONYMOUS | MAP_SHARED
runChildProcess = mmap(NULL, sizeof *runChildProcess, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
if (runChildProcess == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
*runChildProcess = 1; // set to 1 to run the loop
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_sigaction = runTermChildHandler;
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("sigaction SIGUSR1");
exit(EXIT_FAILURE);
}
sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_NOCLDSTOP;
sa.sa_sigaction = termChildHandler;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction SIGCHLD");
exit(EXIT_FAILURE);
}
if (pipe(fd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
char buffer[100];
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) {
close(fd[1]); // close write end of pipe
printf("Child process: %d\n", getpid());
while (*runChildProcess) {
ssize_t nbytes = read(fd[0], buffer, sizeof(buffer)); // block until data is available from parent process
if (nbytes == -1) { // EINTR: interrupted by a signal, although SA_RESTART is set no is no need to check for EINTR
if (errno == EINTR) {
continue;
}else{
perror("read");
exit(EXIT_FAILURE);
}
}
if (nbytes == 0) {
continue;
}
printf("Buffer: %s\n", buffer);
}
close(fd[0]); // close read end of pipe
_exit(EXIT_SUCCESS);
}
printf("Parent process: %d\n", getpid());
close(fd[0]); // close read end of pipe
runChild(fd[1], "Thanks Nate Eldredge");
runChild(fd[1], "Thanks Luis Colorado");
runChild(fd[1], "Thanks www.stackoverflow.com");
termChild(pid, fd[1]);
printf("Done\n");
exit(EXIT_SUCCESS);
}
3 - Semaphore with execve
#include <errno.h>
#include <semaphore.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/stat.h>
struct sigaction sa; // signal
short int *runChildProcess; // mmap shared memory
sem_t *sem; // semaphore
static void handleChildTerm(int signum, siginfo_t *sinfo, void *unused) {
printf("Child %d exited\n", (int)sinfo->si_pid);
}
static void runChild(pid_t pid) {
if (sem_post(sem) == -1) {
perror("sem_post");
exit(EXIT_FAILURE);
}
// When SIGCHLD is caught, sleep(3) is interrupted
// https://stackoverflow.com/questions/14266485/understanding-sigchld-when-the-child-process-terminates
unsigned short int sleepTime = 3;
while ((sleepTime = sleep(sleepTime)) > 0)
;
}
static void termChild(pid_t pid) {
*runChildProcess = 0; // set to 0 to exit the loop
runChild(pid);
signal(SIGCHLD, SIG_DFL); // restore default signal handler
if(munmap(runChildProcess, sizeof *runChildProcess) == -1) {
perror("Munmap");
exit(EXIT_FAILURE);
}
if (sem_destroy(sem) == -1) {
perror("sem_destroy");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[]) {
setbuf(stdout, NULL); // make stdout unbuffered
// mmap: memory mapping file, shared with child process with the flag MAP_ANONYMOUS | MAP_SHARED
runChildProcess = mmap(NULL, sizeof *runChildProcess, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
if (runChildProcess == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
*runChildProcess = 1;
// semaphore
sem = mmap(0, sizeof(*sem), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (sem_init(sem, 1 /*shared*/, 0 /*init val*/) == -1) {
perror("sem_init");
exit(EXIT_FAILURE);
}
// signal handler for SIGCHLD (exit child process)
sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NOCLDWAIT;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handleChildTerm;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction SIGCHLD");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) { // child process
char rootChildPidParam[10];
snprintf(rootChildPidParam, 10, "%d", getpid());
char *childArgv[] = {"process-pipe-fork/execve/myecho", "hello", "world", rootChildPidParam, NULL};
char *childEnviron[] = {"MY_NAME=jcarlosweb", NULL};
printf("Root Child started: %s\n", rootChildPidParam);
while (*runChildProcess) {
sem_wait(sem);
// check again
if (*runChildProcess == 0) {
break;
}
pid_t leafChildPid = fork();
if (leafChildPid == -1) {
perror("fork sibling");
_exit(EXIT_FAILURE);
}
if (leafChildPid == 0) { // child process
printf("Leaf process with execve started: %d\n", getpid());
// TODO: make child process in background
execve("process-pipe-fork/execve/myecho", childArgv, childEnviron);
perror("execve myecho");
_exit(EXIT_FAILURE);
}
}
_exit(EXIT_SUCCESS);
}
printf("Parent process: %d\n", getpid());
runChild(pid);
runChild(pid);
runChild(pid);
termChild(pid);
printf("Done\n");
exit(EXIT_SUCCESS);
}
I'm a c beginner and wrote a multiprocess program. I want to let my child process invoke strace and then pipe to the parent process so that parent process could print it.
But my parent progress seem to be getting stuck in wait(NULL); . I tried commenting code wait(NULL); and I got the output from my child process. I can't figure out why parent process keeping waiting. Hasn't the child process returned yet?
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
int pipefd[2];
pid_t pid;
char *exec_argv[] = { "/bin/strace", "-T", "tree", "/bin", NULL};
char *exec_envp[] = { "PATH=/bin", NULL };
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) { // child
close(pipefd[0]); /* close unused read end */
close(STDOUT_FILENO);
if (dup2(pipefd[1], STDERR_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
// invoke strace
execve(exec_argv[0], exec_argv, exec_envp);
perror(exec_argv[0]);
exit(EXIT_FAILURE);
} else { // parent
close(pipefd[1]); /* close unused write end */
if (dup2(pipefd[0], STDIN_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
printf("I'm parent!!!\n");
wait(NULL);
char *line = NULL;
size_t len;
while (getline(&line, &len, stdin) != -1) {
printf("%s", line);
}
free(line);
}
return 0;
}
You didn't close pipefd[0] in the parent.
You didn't close pipefd[1] in the child.
Another problem is that your code is susceptible to deadlocks. If the child writes enough to the pipe to fill it, it will block until it has space to accept more. And since the the pipe is not emptied until the child exits, the child will never unblock.
This is easy to fix: Read until EOF, then call wait to reap the child. In other words, move the wait so it's after the loop.
I am working on a ncurses based file manager in C. The problem is that some child processes can take some time to complete and till that happens it remains stuck due to waitpid.
I can't use the WNOHANG flag because the next block of code is dependent on the output of the child process.
void getArchivePreview(char *filepath, int maxy, int maxx)
{
pid_t pid;
int fd;
int null_fd;
// Reallocate `temp_dir` and store path to preview file
char *preview_path = NULL;
allocSize = snprintf(NULL, 0, "%s/preview", cache_path);
preview_path = malloc(allocSize+1);
if(preview_path == NULL)
{
endwin();
printf("%s\n", "Couldn't allocate memory!");
exit(1);
}
snprintf(preview_path, allocSize+1, "%s/preview", cache_path);
// Create a child process to run "atool -lq filepath > ~/.cache/cfiles/preview"
pid = fork();
if( pid == 0 )
{
remove(preview_path);
fd = open(preview_path, O_CREAT | O_WRONLY, 0755);
null_fd = open("/dev/null", O_WRONLY);
// Redirect stdout
dup2(fd, 1);
// Redirect errors to /dev/null
dup2(null_fd, 2);
execlp("atool", "atool", "-lq", filepath, (char *)0);
exit(1);
}
else
{
int status;
waitpid(pid, &status, 0);
getTextPreview(preview_path, maxy, maxx);
free(preview_path);
}
}
In this case, I would like to carry forward with the rest of the program if the user decides to go to some other file. In what way can I change the architecture of the program?
If I have understood the question correctly then you want to unblock parent on either completion of child or any user input.
As suggested in this comment, you could handle SIGCHLD and one more signal say SIGUSR1. SIGUSR1 will be raised when you get user input. Following is the example where both SIGCHLD and 'SIGUSR1' is handled. If use inputs any number then it raises SIGUSR1 to parent and parent kill child. Else child will raise SIGCHLD on exit.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int raised_signal = -1;
static void cb_sig(int signal)
{
if (signal == SIGUSR1)
raised_signal = SIGUSR1;
else if (signal == SIGCHLD)
raised_signal = SIGCHLD;
}
int main()
{
int pid;
int i, a;
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = cb_sig;
if (sigaction(SIGUSR1, &act, NULL) == -1)
printf("unable to handle siguser1\n");
if (sigaction(SIGCHLD, &act, NULL) == -1)
printf("unable to handle sigchild\n");
pid = fork();
if (pid == 0) {
/* child */
for (i = 0; i < 10; i++) {
sleep(1);
printf("child is working\n");
}
exit(1);
} else {
/* parent */
if (-1 == scanf("%d", &a)) {
if (errno == EINTR)
printf("scanf interrupted by signal\n");
} else {
raise(SIGUSR1);
}
if (raised_signal == SIGUSR1) {
printf("user terminated\n");
kill(pid, SIGINT);
} else if (raised_signal == SIGCHLD) {
printf("child done working\n");
}
exit(1);
}
return 0;
}
This is my code.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
int file,parentID,childID;
pid_t pid;
int main(int argc, char *argv[])
{
if( argc != 2 )
{
printf("ERROR ! You have not write an argument\n");
printf("ERROR ! You give more than one argument");
return 1;
}
file = open(argv[1], O_RDONLY); //open file
if(file<0) //test the file
{
printf("Error open file\n");
printf("ERROR : %s\n", strerror(errno));
return 1;
}
// ---------------------------------------------------------------------
pid = fork();
if( pid == -1) //error fork
{
printf("Error fork\n");
return 1;
}
if(pid == 0) // child process
{
childID = getpid();
printf("Child process %d\n",childID);
// if(childID %2 == 1)
// {
// parentID = getppid();
// printf("Process of father of this child= %d\n",parentID);
// }
}
if( pid == 1)
{
parentID = getppid();
printf("ParentProcess %d\n",parentID);
}
}
I have to write a program to create a child process.Depending on the parity of the child process , the parent should transmit to child a message through a file , the message being taken over and showed by the child process( if the child process is a number that is divizible with 2 it will say -"Good morning!" else "Good night!" ).The parent should wait for the final execution of the child to terminate.
I'm trying really hard to do this exercise and i can't find anywere to explain me how or what function/structure object should i use to do this.Above i tried but i failed , and i understand somehow how fork does but... please help me with this code , or suggest me were should i go to read to make this exercise .Sorry for my bad english spelling.
What documentation are you using for the system calls?
There are a number of ways to do this, but what you probably want to do is create a pipe, and then fork the process. Since a fork copies everything, and child processes inherit the environment, each process has a copy of the file descriptors for the pipe. You can then read/write based on the return value of fork().
int main(int argc, char *argv[])
{
int fd[2];
char in[128], out[128];
if( argc != 2 )
{
printf("ERROR ! You have not write an argument\n");
printf("ERROR ! You give more than one argument");
return 1;
}
if (pipe(fd) == -1)
return 1;
// ---------------------------------------------------------------------
pid = fork();
if (!pid)
read(fd[0], in, 128);
else
write(fd[1], out, strlen(out) + 1);
pipe(2)
note, you usually want to close the file descriptor you're not using for one way communication
I think this is the code.
#include <stdio.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void sighandler (int sig)
{
if (sig == SIGUSR1)
{
FILE *f;
char line[100];
f = fopen("file","r");
fgets(line, 100, f);
printf ("Procesul copil cu pid %d a primit mesajul %s", getpid(), line);
fclose(f);
}
}
int main ()
{
pid_t pid;
FILE * f;
pid = fork();
if (pid < 0)
{
perror ("Eroare la fork()");
return (1);
}
else
if (pid == 0)
{
signal (SIGUSR1, sighandler);
pause();
return 0;
}
else
{
if (pid % 2 == 0)
{
printf ("Notificam procesul fiu cu pid %d", pid);
f = fopen ("file","w");
fprintf (f,"Good morning!");
fclose(f);
kill (pid, SIGUSR1);
}
else
{
printf ("Notificam procesul fiu cu pid %d", pid);
f = fopen ("file","w");
fprintf (f,"Good night!");
fclose(f);
kill (pid, SIGUSR1);
}
}
wait(NULL);
return 0;
}