This is a strange question. I have 2 different program:
server and client.
server start, alloc all the message queue and start to waitin for a signal from client (the signal is for tell to the server that "there are new message").
the server remain in an infinite loop until recive SIGQUIT.
the client, when casted, start to send a huge number of message to the server
for(;;){//infinite loop
wait(sem,1); //wait for new message
rc = msgctl(msgid, IPC_STAT, &qbuff);
seq_num++;
pid=fork(); //new process for take the message
if(!pid){
if((msgrcv(msgid, &q, msgsz, 1,MSG_NOERROR))== -1)
perror("msgrcv error");
else{
pthread_mutex_lock(&mutex); //start critic sector
printf("\nthere is a prenotation\n");
q.price=get_conf_value(q.kindof_service)+(q.priority*get_conf_value(3)); //costo = costo_visita + (priorità * costo_priorità)
q.turn=seq_num-q.priority; //assign turn
pthread_mutex_unlock(&mutex); //end critic sector
if(q.turn<0)q.turn=0; //controllo del turno che non sia minore di 0
printf("---------------------------");
printf("\nPrenotation number %i\npid caller: %i\npriorità: %i\n for %i\ncost %i\nturn %i\n",seq_num,q.clientId,q.priority, q.kindof_service ,q.price, q.turn);
printf("---------------------------\nPrenotation ok\n\n\n");
}
printf("\nsuccess.\n");
exit(1); //close children process
}
}
The problem is that, in this way the father leave so much zombies. If i add
else{//i am the father
waitpid(pid, 0, 0);
}
there is the problem that the primary process fork, then wait until the child is ended, then fork again.
i need that the father fork so many time and that dont wait the end of the process before fork again.
But without the waitpid the problem is another.. because after that he start all the process needed for receive all the message, the father take the control and still waitin for another signal from the client (the first wait(sem,1) ), leaving so much zombie process.
I don't know if I explained it well.. is very difficult in english -_-
So, i want a server that, received the signal, fork many many times. any child take a message and do some stuff, then the child end. Meanwhile the server continue to wait for new incoming message. All without make zombies :)
One way to fire-and-forget processes without having to worry about zombies is to fork twice.
Each process has a parent process. If the parent process exits before the child does, the child is becoming an orphan, and is inherited by init (process 1) - which will wait for all children, preventing them to become zombies without manual work.
So what you can do is to fork, and fork yet again in the child process. Then, you can let the child exit, which will cause the grandchild (where you do your work) to be inherited by init. The parent process can wait for the child (which won't take long, because the child did nothing else than fork and exit). When the grandchild is exiting, init will automatically wait for it.
/* fire and forget */
int execute_detached(char **cmdline)
{
pid_t pid;
if((pid = fork()) < 0) { /* fork error */
perror("fork");
return 0;
}
else if(pid > 0) { /* parent */
waitpid(pid, NULL, 0);
return 1;
}
else { /* child */
if((pid = fork()) < 0) { /* fork error */
perror("fork");
return 0;
}
else if(pid > 0) { /* child */
/* make grand child an orphan */
_exit(0);
}
else { /* grand child */
execvp(cmdline[0], cmdline);
perror("execvp");
_exit(1);
}
}
return 0;
}
Related
In my program, each time the user types a message via stdin, the code reads it in, and calls fork() to create a new (child) process. This child process sends data (the user's typed in message) using a server socket.
To end the client process, I would like the user to type "quit". At which point, I would like my code to exit the While(1) loop, wait for all the child processes to finish processing (so leaving behind no orphaned/zombie processes). And then at this point, when all the child processes have finished and exited, I would like the program to end.
However now and with my code as shown below, when the user types "quit", although the child processes terminate successfully, the loop starts over. Does any one know what am I doing wrong in the code?
int status = 0;
while (1) {
// Read request from standard input
printf("Enter a message: ");
memset(out_buffer, 0, BUFFER_SIZE);
fgets(out_buffer, BUFFER_SIZE - 1, stdin);
out_buffer[strcspn(out_buffer, "\r\n")] = 0;
// Spawn new process to handle new client
if ((pid = fork()) == -1) {
printf("[-]Error spawning child process for new client.\n");
continue;
}
// Child process
else if (pid == 0) {
// ...
if (input_status == -2) {
printf("[-]Disconnected from server.\n");
close(socket_fd);
termination_call = 1;
exit(0);
}
}
if (termination_call == 1) {
printf("[-]Client terminating...\n");
break;
}
}
// Wait for all child processes to exit
while ((wpid = wait(&status)) > 0);
return 0;
You need to check for the "quit" command in the parent.
When you fork a new process, it runs independent of the parent process, and no data is shared between them.
If you want to share data then consider threads.
I'm trying to change the pgrp of the processes to that of the child's so i can setsid on the parent process. The only thing is I keep getting an EPERM error code. Both processes have the same session group, according to htop.
I'm basing this off of this blog post, so I can change which terminal output gets directed to.
void sig_exit(int signum)
{
_Exit(0);
}
pid_t change_process_group()
{
pid_t child_pid;
if ((child_pid = fork()) < 0)
{
perror("fork failed while attaching to term");
exit(1);
}
if (child_pid == 0)
{
pid_t parent = getppid();
setpgid(0, getpid());
signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
//sleep(5);
//kill(parent, SIGUSR2);
pause();
printf("Shouldn't reach this\n");
}
//sleep(5);
//signal(SIGUSR2, sig_wait);
//pause();
int parent_pid = getpid();
int code = setpgid(parent_pid, child_pid); // need child process group
printf("%s\n", strerror(errno));
setsid();
return child_pid;
}
main()
{
pid_t child = change_process_group();
kill(child, SIGUSR1);
}
The commented out lines were from me thinking the processes might not be executing in the correct order, but those don't appear to fix the problem.
How may I correctly use setpgid to change the pgrp of the parent process to the child's?
This is a race condition and it works if you uncomment the sleep(5) line in the parent. When you call setpgid(parent_pid, child_pid), the child_pid process group must exist. It isn't enough that there exists a process with the PID child_pid: setpgid needs an existing process group unless the process is putting itself into its own group. If setpgid(parent_pid, child_pid) in the parent runs after setpgid(0, getpid()) in the child, it works.
Sleeping is both inefficient and fragile, so instead of that the parent should wait for a notification from the child. Signals are fragile because there aren't many different signals and they could come from anywhere. A good way to communicate between related processes is a pipe. Since all you need here is a one-time notification, you can set up a pipe and read from it in the parent (with the write end closed in the parent). The parent will wait until the child writes to the pipe or closes it. In the child, just close the write end of the pipe when you've finished the preparations. The parent's read call (or select if you need to do other things at the same time) will return.
Proof-of-concept code:
pid_t change_process_group()
{
pid_t child_pid;
int child_ready_pipe[2];
if (pipe(child_ready_pipe) < 0)
{
perror("pipe");
exit(1);
}
if ((child_pid = fork()) < 0)
{
perror("fork failed while attaching to term");
exit(1);
}
if (child_pid == 0)
{
close(child_ready_pipe[0]);
sleep(1); // mimic slow start of the child
if (setpgid(0, 0))
perror("child setpgid to create group");
close(child_ready_pipe[1]);
signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
pause();
printf("Shouldn't reach this\n");
}
close(child_ready_pipe[1]);
int parent_pid = getpid();
char ignored;
read(child_ready_pipe[0], &ignored, 1);
close(child_ready_pipe[0]);
if (setpgid(parent_pid, child_pid) < 0) // need child process group
perror("parent setpgid");
if (setsid() < 0)
perror("parent setsid");
return child_pid;
}
I am writing a program that needs to fire another program for a number of seconds, then close it.
Feedback from the program's console would be useful, if possible.
I imagine I would close the program by retrieving the pid from the child process and running a pkill?
What would be the best way to go about this?
Thanks in advance
EDIT BY OP
void mountAd(char* adFilePath){
char* mountPoint = getNextAvailableMount();
// Set Playlist ready to be played
editPlaylist(mountPoint, adFilePath);
// Fork process and fire up ezstream
int pid = fork();
if(pid == 0){
puts ("Child Process Here\n");
execl ("/usr/local/bin/ezstream","/usr/local/bin/ezstream", "-c", "/home/hearme/radio/_test_adverts/advert01.xml", NULL);
perror("execl");
} else {
puts ("Parent Process Here\n");
}
// Advised sleep for 3 seconds until ezstream has started
sleep(3);
// More stuff to do here later
kill(pid, SIGTERM);
waitpid(pid, NULL, 0);
}
Something like this should work:
pid = fork();
if (pid < 0)
/* fork failed, error handling here */
if (pid == 0) {
/* we are the child, exec process */
execl(...);
/* this is only reached if execl fails */
perror("execl");
/* do not use exit() here, do not return from main() */
_Exit(EXIT_FAILURE);
}
/* we are the parent */
sleep(duration);
kill(pid, SIGKILL);
/* use wait/waitpid/waitid as needed */
waitpid(pid, NULL, 0);
Notice that this does not correctly perform error checking for the case when the program you want to run cannot be found or executed, a more elaborate scheme is needed for that case, if you are interested I could elaborate.
I'm hoping someone could shed some light on how to make the parent wait for ALL child processes to finish before continuing after the fork. I have cleanup code which I want to run but the child processes need to have returned before this can happen.
for (int id=0; id<n; id++) {
if (fork()==0) {
// Child
exit(0);
} else {
// Parent
...
}
...
}
pid_t child_pid, wpid;
int status = 0;
//Father code (before child processes start)
for (int id=0; id<n; id++) {
if ((child_pid = fork()) == 0) {
//child code
exit(0);
}
}
while ((wpid = wait(&status)) > 0); // this way, the father waits for all the child processes
//Father code (After all child processes end)
wait waits for a child process to terminate, and returns that child process's pid. On error (eg when there are no child processes), -1 is returned. So, basically, the code keeps waiting for child processes to finish, until the waiting errors out, and then you know they are all finished.
POSIX defines a function: wait(NULL);. It's the shorthand for waitpid(-1, NULL, 0);, which will suspends the execution of the calling process until any one child process exits.
Here, 1st argument of waitpid indicates wait for any child process to end.
In your case, have the parent call it from within your else branch.
Use waitpid() like this:
pid_t childPid; // the child process that the execution will soon run inside of.
childPid = fork();
if(childPid == 0) // fork succeeded
{
// Do something
exit(0);
}
else if(childPid < 0) // fork failed
{
// log the error
}
else // Main (parent) process after fork succeeds
{
int returnStatus;
waitpid(childPid, &returnStatus, 0); // Parent process waits here for child to terminate.
if (returnStatus == 0) // Verify child process terminated without error.
{
printf("The child process terminated normally.");
}
if (returnStatus == 1)
{
printf("The child process terminated with an error!.");
}
}
Just use:
while(wait(NULL) > 0);
This ensures that you wait for ALL the child processes and only when all have returned, you move to the next instruction.
I am writing a mapreduce program that uses multiple I/O pipes (one pipe per process) to get some final results. I am having a problem with creating the processes. Specifically, I am getting the following error:
wait error: Interrupted system call
This is my code that spawns processes:
while (values[inc]!=NULL) //provided array of text lines
{
if ((pid = fork()) == -1) {
perror("fork error");
exit(EXIT_FAILURE);
}
else if (pid == 0) { /* start of child process */
printf("Child process...\n");
/* pipes[inc][1] is a file descriptor to which myMap writes some data
using the write() system call
mr is a struct that holds other function pointers */
mr->myMap(pipes[inc][1],values[inc]);
exit(0);
}
else { /* start of parent process */
printf("Parent process...\n");
if ((wpid = wait(&status)) == -1)
/* Wait for child process. */
perror("wait error");
else { /* Check status. */
if (WIFSIGNALED(status) != 0)
printf("Child process ended because of signal %d\n",
WTERMSIG(status));
else if (WIFEXITED(status) != 0)
printf("Child process ended normally; status = %d\n",
WEXITSTATUS(status));
else
printf("Child process did not end normally\n");
}
//close(fd[1]);
printf("Parent process ended\n");
}
inc++;
}
After this I am creating one thread
pthread_t newThread;
pthread_create(&newThread,NULL,threadFunction,values);
pthread_join(newThread,NULL);
The threadFunction uses select() function to find out which file descriptor is ready to be read and reads it and puts data in a dictionary.
When running form gdb debugger, the program output:
Parent process...
Child process...
wait error: Interrupted system call
Parent process ended
Parent process...
Child process ended normally; status = 0
Parent process ended
Parent process...
Child process...
Child process...
wait error: Interrupted system call
Parent process ended
I don't know how to resolve the issue. Any suggestions?
Thanks!
You need to put your wait() call into a loop and if it returns an error (-1) and errno == EINTR continue the loop. Any other error is a real error and should be treated as such.
Things like profiling timers can cause signals to be sent to the process, however the signal probably causing the interruption is SIGCHLD, which as you know is called when a child process changes state.
EDIT: OK, I'll write the answer in code:
do
{
wpid = wait(&status);
}
while (wpid == -1 && errno == EINTR);
if (wpid == -1)
{
perror("wait error");
return -1;
}
else
{
// we have wait status
...
}