I am trying to create a daemon that forks two processes that will run infinitely to check time and receive messages between processes. When I run the program without the steps to create a daemon it all works fine. However once I try to create a daemon, it seems the child processes I fork become zombies.
This is the output of ps -ajx
2678 3628 3628 2678 pts/2 3628 S+ 1000 0:00 ./assignment_daemon
3628 3629 3629 3629 ? -1 Zs 1000 0:00 [assignment_daem] <defunct>
And here is the C code,
int main()
{
int pid = fork();
if(pid > 0)
{
printf("Parent process..\n");
sleep(10);
exit(EXIT_SUCCESS);
}
else if (pid == 0)
{
printf("Child process..\n");
if(setsid() < 0)
{
exit(EXIT_FAILURE);
}
umask(0);
if(chdir("/") < 0)
{
exit(EXIT_FAILURE);
}
int x;
for(x = sysconf(_SC_OPEN_MAX); x>=0;x--)
{
close(x);
}
openlog("assignment_daemon", LOG_PID|LOG_CONS,LOG_USER);
syslog(LOG_INFO,"assignment_daemon started...");
int SIZE = 2;
pid_t child_pids[SIZE];
int num_of_children = SIZE;
for(int i = 0; i < num_of_children; i++)
{
if((child_pids[i] = fork()) < 0)
{
perror("Error: failed to fork!\n");
syslog(LOG_ERR,"failed to fork...");
exit(EXIT_FAILURE);
}
else if(child_pids[i] == 0){
if(i == 0)
{
syslog(LOG_INFO,"Forked message_server...");
//run message server
char * argv_list[] = {"message_queue_server",NULL};
execv("./assignment_queue_server",argv_list);
}
if(i == 1)
{
syslog(LOG_INFO,"Forked time_check...");
//run time check
char * argv_list[] = {"time_check_process",NULL};
execv("./time_check_process",argv_list);
}
}
}
int status;
pid_t pid;
while(num_of_children > 0)
{
pid = wait(&status);
printf("Child %d exited with status 0x%x\n",pid,status);
syslog(LOG_INFO,"child has exited...");
num_of_children--;
}
syslog(LOG_INFO,"assignment_daemon ended...");
}
return 0;
}
Any help would be appreciated.
Thanks.
Related
I've included code that creates a series of child processes to divide the work for a task. There's a random chance for it to terminate (handled by the word_count function from which it calls abort()) and on this event, it should create a new child process to replace it. However, the program is being blocked on the read. I know this code is messy, but I want understand the problem before cleaning it up.
int pipes[nChildProc][2]; //pipe fd[0] is read end, fd[1] is write end
long child_f_size = fsize / nChildProc;
pid_t pids[nChildProc];
//start dividing the work among child processes
for(int i = 0; i < nChildProc; ++i) {
//srand(time(NULL));
//int crash = ((rand() / RAND_MAX + 1.0) < crashRate) ? 1 : 0;
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
//wait for a children to finish
int ret, status, i = 0;
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
if(ret == -1) {
continue;
}
if(ret != 0) {// didn't exit normally
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
i = (i + 1) % nChildProc;//loop back to detect more processes that were terminated
}
long bytes;
count_t temp;
temp.linecount = 0;
temp.wordcount = 0;
temp.charcount = 0;
//add up all the values from children to count
printf("time to read.\n");
for(unsigned int j = 0; j < nChildProc; ++j) {
if((bytes = read(pipes[j][0], &temp, sizeof(temp))) < 0) {//blocked here
printf("Failed to read from pipe {%d}.\n", j);
exit(1);
}
if(bytes != 0) {
count.linecount += temp.linecount;
count.wordcount += temp.wordcount;
count.charcount += temp.charcount;
}
close(pipes[j][1]);
close(pipes[j][0]);
}
A couple of issues jump out:
if(ret != 0) {// didn't exit normally you've confused ret (which is the pid) for status (which is the exit code of the child)
You can't call wait on a process twice, since calling wait allows the system to release the resources associated with the process. You have several options on how to rewrite this code:
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
One easy way is to use wait then lookup in the array which index it belongs to.
while((pid = wait(&status)) {
if (pid == -1) { // no children to wait on
break;
}
for(int i = 0; i < nChildProc; ++i) {
if (pid == pids[i]) break;
}
if (i >= nChildProc) {
unexpected_pid_do_something_smart();
}
// Leave the rest of the loop the same
Note: I didn't compile or test the above code.
I have picked the following example from APUE :
void daemonize(const char* cmd)
{
int i,fd0,fd1,fd2;
pid_t pid;
struct rlimit r1;
struct sigaction sa;
//clear all file masks
umask(0);
//get max number of file descriptors
if(getrlimit(RLIMIT_NOFILE,&r1) < 0)
{
perror("error getting file descriptor size");
return;
}
//become a session leader
if((pid = fork()) < 0)
{
perror("error forking");
return;
}
else if(pid == 0)
{
setsid();
}
else
{
exit(0); //parent exits
}
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if(sigaction(SIGHUP,&sa,NULL) < 0)
{
return;
}
if((pid = fork()) < 0)
{
return;
}
else if(pid != 0)
{
exit(0); //parent
}
//child continues
syslog(LOG_ERR,"chile continuing with pid : %d",getpid());
//change the working directory
if(chdir("/") < 0)
{
return;
}
if(r1.rlim_max == RLIM_INFINITY)
r1.rlim_max = 1024;
for(i=0;i<r1.rlim_max;i++)
close(i);
//attach the file descriptors to /dev/null
fd0 = open("/dev/null",O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
//initialize the log file
openlog(cmd, LOG_CONS,LOG_DAEMON);
if(fd0!=0 || fd1!=1 || fd2!=2)
{
syslog(LOG_ERR,"unexpected file descriptors %d %d %d\n",fd0,fd1,fd2);
exit(1);
}
}
int main()
{
daemonize("date");
pause(); //how is this working???
}
What I don't understand is how the pause() from the main function is working? What I was expecting is that since we have done exit(0) for the parent process in daemonize(), it should have exited and resulted in the normal termination of the main() process. It should have never returned to the main() and the call to pause() should not even happen. Why it did not terminate and why the pause() got called?
The code forks twice, producing a parent, a child, and a grandchild. The first two each exit(0); the last returns from daemonize.
I want to fork 3 child processes and have each process execute a function and busy wait until they are complete. The 3rd process is a countdown timer so once the runtime reaches 0 I will use an IPC to tell the other processes to exit. I have written the functions besides the IPC part and they run individually but I can't get fork() to create the 3 child processes to each execute a specific function.
int main(int argc, char *argv[]) {
pid_t child_onepid, child_twopid, child_threepid, pid;
for (i = 0; i < 3; ++i) {
pid = fork();
if (pid) {
continue;
} else if (pid == 0 && i == 0) {
show_time();
} else if (pid == 0 && i == 1) {
show_uptime();
} else if (pid == 0 && i == 2) {
show_timer(runtime);
} else {
printf("fork error\n");
exit(1);
}
}
return EXIT_SUCCESS;
}
This is my output
Time: 06/28/2014 18:55:57PM
Timer: 00:09
>Timer: 00:09
6:55pm up 171 day(s), 10:49, 17 users, load average: 0.34, 0.38, 0.43
6:55pm up 171 day(s), 10:49, 17 users, load average: 0.34, 0.38, 0.43
Your code looks fine to me, except your error test will never hit because the if(pid) will trigger on -1.
Besides that, are you supper sure that your functions are not returning and then going around their own copy of the for loop, that would explain the output... so I added some break to make sure of that.
But I've not tested the code.
int main(int argc, char *argv[]) {
pid_t pid;
for (int i = 0; i < 3; ++i) {
pid = fork();
if (pid == -1) {
perror("fork error\n");
exit(EXIT_FAILURE);
} else if (pid > 0)
continue;
} else if (i == 0) {
show_time();
break;
} else if (i == 1) {
show_uptime();
break;
} else if (i == 2) {
show_timer(runtime);
break;
}
}
return EXIT_SUCCESS;
}
I am trying to run N concurrent processes in a C program. I've built a simple example that takes commands as arguments, creates a fork for each one, and executes it.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "forking error\n");
exit(1);
}
else if(pid > 0)
{
int status;
waitpid(pid, &status, 0);
printf("Command %s has completed successfully by PID=%d\n", argv[i], pid);
}
else
{
char cmd[1024];
sprintf(cmd, "%s", argv[i], i);
system(cmd);
_exit(1);
}
}
printf("Finished\n");
return 0;
}
This seems to run the processes correctly, but not concurrently. Any ideas as to what am I doing wrong?
EDIT: I've edited based on suggestions, but this also does not seem to work.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
pid_t *pids = malloc( sizeof(pid_t) * (argc) );
int *statuses = malloc( sizeof(int) * (argc) );
for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "forking error\n");
exit(1);
}
else if(pid > 0)
{
//int status;
//waitpid(pid, &status, 0);
//printf("Command %s has completed successfully by PID=%d\n", argv[i], pid);
pids[i] = pid;
}
else
{
char cmd[1024];
sprintf(cmd, "%s > out.%d", argv[i], i);
system(cmd);
_exit(1);
}
}
int needtowait = 0;
do
{
needtowait = 0;
for(i = 1; i < argc; i++)
{
if(pids[i] > 0)
{
if(waitpid(pids[i], &statuses[i], 0) != 0)
{
pids[i] = 0;
char *successstr = "successfully";
if(statuses[i])
{
successstr = "unsuccessfully";
}
printf("Command %s has completed %s by PID=%d\n", argv[i], successstr, pids[i]);
}
}
else
{
needtowait = 1;
}
sleep(0);
}
} while(needtowait);
printf("Finished!\n");
return 0;
}
The reason you are not running these processes concurrently is in this line:
waitpid(pid, &status, 0);
The main process that forks out the child process waits for the child process to exit before continuing with the loop, and starting the next process.
Since you want to run your processes concurrently, you can do this: allocate an array of pid_t for process IDs, and fill it in inside the loop. Once you are out of the loop, you can wait for the individual processes to complete by executing waitpid calls in a loop.
pid_t *pids = malloc(argc * sizeof(pid_t));
for (int i = 0 ; i < argc ; i++) { // Start i at 0, not at 1
pid_t pid = fork();
if (pid < 0) {
...
} else if (pid > 0) {
pids[i] = pid;
} else {
char cmd[1024];
sprintf(cmd, "%s", argv[i+1], i+1);
system(cmd);
_exit(1);
}
}
for (int i = 0 ; i < argc ; i++) {
int status;
waitpid(pids[i], &status, 0);
printf("Command %s has completed successfully by PID=%d\n", argv[i+1], pids[i]);
}
Sure. Your parent process is waiting for the child process to finish executing before forking again. You're just running cmd sequentially N times.
I'm trying to pipe in C in parallel but for some reason it's not closing... it's just waiting.... Not sure if I'm describing this well cuz i'm new at this, but here's the code
... some code up here
if(child_pid == 0) {
if(p0 >=0 && p1 == -1) {
dup2(p0, STDIN_FILENO);
close(p0);
close(p1);
}
else if (p0 == -1 && p1 >= 0) {
dup2(p1, STDOUT_FILENO);
close(p0);
close(p1);
}
else if (p0 >= 0 && p1 >=0) {
dup2(p0, STDIN_FILENO);
dup2(p1, STDOUT_FILENO);
close(p0);
close(p1);
}
if (input)
iofunc(input, 0);
if (output)
iofunc(output, 1);
if (sub){
command_exec (SUBSHELL_COMMAND, sub, -1, -1, -1);
exit(0);
}
else {
execvp(w[0], w);
exit(0);
}
}
else {
if (waitpid (-1, &child_status, 0) != child_pid)
child_status =-1;
close(p0);
close(p1);
return WEXITSTATUS(child_status);
}
... some code down here
when p0 == -1 && p1 >= 0, the process exits/returns, but for some reason, when p0 >= 0 && p1 == -1, the process just hangs and the pipe doesn't close. I ran a command ls | cat using two parallel child processes with ls writing to p1 and the cat reading from p0. The output was correct, but the pipe didn't close and cat never exited. What is going on?
#William I tried the following in my parent else block, but it didn't work
close(p0);
close(p1);
if (waitpid (-1, &child_status, 0) != child_pid)
child_status =-1;
#William here is the code that calls a function that calls the above code
int i = 0;
int num = 2;
int status;
pid_t pid;
pid_t pids[num];
int fd[2];
int p = pipe(fd);
int a;
int b;
//printf("pipe0:%d\n", fd[0]);
//printf("pipe1:%d\n", fd[1]);
for (i = 0; i < num; i++) {
if ((pids[i] = fork()) < 0) {
error(1,0, "child not forked");
} else if (pids[i] == 0) {
if (i == 0){
b = command_exec (c->type,
c->u.command[1],
0, f[0], p1);
}
else if (i == 1){
a = command_exec (c->type,
c->u.command[0],
1, p0, fd[1]);
}
exit(a && b);
}
}
while (num > 0) {
pid = wait(&status);
printf("Child with PID %ld exited with status 0x%x.\n", (long)pid, status);
num--;
}
The printf only prints the child process that finishes ls but not cat
Most likely, the parent is holding open the other side of the pipe. The ls has an open file descriptor on the write side of the pipe into cat, but so does the parent. cat will not exit until all the write side file descriptors are closed. Probably, you just need to reverse your code and close the pipes before you call waitpid instead of after.