Wait for a Forked Process when using a Semaphore - c

I'm trying to code an exercise in C Linux where I have one semaphore with 2 spots and "n" processes entered by argument. I need that the first 2 processes use the semaphore using the 2 spots for 5 secs each and then leave the semaphore for the other remaining processes to do their stuff. The problem is that not all the other processes wait for the semaphore to be free and some of them show a semaphore error (look at the results at the bottom). I believe the problem is on the waits for the child processes, because I have a waitipid and a wait function, but I need that if there's a free spot in the semaphore, any child process running could use it. Here's the code:
//gcc SemaphoreExample.c -o s
//./s 5
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
void semaphoreTask(int semid, int semnum, int semBusy)
{
struct sembuf data;
data.sem_num = semnum;
data.sem_flg = 0;
data.sem_op = semBusy;
if(semop(semid,&data,1) == -1)
{
printf("\nSemaphore Error\n");
exit(-1);
}
}
int main(int argc, char *argv[])
{
int i, fdSemaphore, quantity, fdsemctl, j;
pid_t pid[15];
system("clear");
if(argc-1 < 1)
{
printf("Some arguments are missing\n");
return EXIT_FAILURE;
}
printf("Number of arguments entered:\n\nargc: %d\n\nValues from the arguments:\n\n",argc-1);
for(i=0;i<argc;i++)
{
printf("argv[%d]: %s\n",i,argv[i]);
}
printf("\n\n");
fdSemaphore = semget(1234,1,IPC_CREAT|0777);
if(fdSemaphore == -1)
{
printf("\nError creating the Semaphore\n");
return EXIT_FAILURE;
}
fdsemctl = semctl(fdSemaphore,0,SETVAL,2);
if(fdsemctl == -1)
{
printf("\nError opening the Semaphore\n");
return EXIT_FAILURE;
}
quantity = atoi(argv[1]);
for(i=0;i<quantity;i++)
{
pid[i] = fork();
if(pid[i] == -1)
{
printf("\nError creating the Child Process\n");
return EXIT_FAILURE;
}
if(pid[i] == 0)
{
semaphoreTask(fdSemaphore,0,-1);
printf("\n[%d] I go to sleep\n",getpid());
sleep(5);
printf("\n[%d] I wake up\n",getpid());
semaphoreTask(fdSemaphore,0,1);
}
else
{
//printf("\nJust wait\n");
waitpid(pid[i],NULL,WNOHANG);
}
}
for(j=0;j<quantity;j++)
{
wait(NULL);
}
semctl(fdSemaphore,0,IPC_RMID);
return EXIT_SUCCESS;
}
This is the result I got:
Result:
Number of arguments entered:
argc: 1
Values from the arguments:
argv[0]: ./s
argv[1]: 5
[2845] I go to sleep
[2844] I go to sleep
[2845] I wake up
[2844] I wake up
Semaphore Error
[2843] I go to sleep
Semaphore Error
Semaphore Error
[2843] I wake up
Semaphore Error
Should I use wait or waitpid only?

The problem is semaphores are getting removed by forked children.
After line
semaphoreTask(fdSemaphore,0,1);
add
exit(0);

It is much simpler to implement what you want if you use sem_post and sem_wait calls. I am on a OpenBSD system and I am assuming that Linux has the same thing.

Related

How to send a signal from the child process to parent process through kill command

I am trying to create a child process through fork() system call, then trying to send a signal to parent and print out something on the screen.
Here is my code:-
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void func1(int signum) {
if(signum == SIGUSR2) {
printf("Received sig from child\n");
}
}
int main() {
signal(SIGUSR2, func1);
int c = fork();
if(c > 0) {
printf("parent\n");
}
else if(c == -1) {
printf("No child");
}
else {
kill(getppid(), SIGUSR2);
printf("child\n");
}
}
When I execute my program all I get is:-
child
Segmentation fault (core dumped)
I am a novice to C language system calls, and don't get why this is happening, and how to get the desired output, which would be printing of all the three printf statements. Any help for the same would be appreciated.
Your code has a number of minor issues and certainly has undefined behaviour i.e., you can't call printf or other async-signal unsafe functions from a signal handler.
This is the code with fixes (see comments in code). This should work as expected (with no particular order of print statements) and see if still get a segfault with this code.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void func1(int signum)
{
/* write is asyc-signal-safe */
write(1, "Received sig from child\n", sizeof "Received sig from child\n" - 1);
}
int main()
{
signal(SIGUSR2, func1);
/* fork returns a pid_t */
pid_t c = fork();
if(c > 0) {
printf("parent\n");
/* Wait for the child to exit; otherwise, you may not receive the signal */
if (wait(NULL) == -1) {
printf("wait(2) failed\n");
exit(1);
}
} else if (c == -1) {
printf("fork(2) error\n");
exit(1);
} else {
if (kill(getppid(), SIGUSR2) == -1) {
/* In case kill fails to send signal... */
printf("kill(2) failed\n");
exit(1);
}
printf("child\n");
}
}

C - threads and processes - prevent zombies

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.

why pThread exit causes main process termination?

I'm testing based on linux 2.6.21 and pThread library.
I tried several cases in order to find out workaround how to avoid main process termination. But, I didn't find out it.
Please, tell me why exiting of thread function causes main process to be terminated?
Here is test code below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <linux/input.h>
#include <fcntl.h>
#include <errno.h>
#include <dlfcn.h>
#include <time.h>
#include <pthread.h>
int handle = 0;
int main_loop = 0;
void *testThread(void *pParm)
{
int i;
for (i=0; i < 5 ; i++){
printf("====testThread loop %d\n", i);
sleep(1);
}
if (main_loop == 1){
exit(0);
}
else if (main_loop == 2)
{
sleep(10);
exit(0);
}
else if (main_loop == 3)
{
pthread_exit(NULL);
}
else if (main_loop == 4)
{
sleep(10);
pthread_exit(NULL);
}
}
int main(int argc, char *argv[])
{
pthread_t pTestThread;
int i, ret;
if (argc == 2){
main_loop = atoi(argv[1]);
}
if (argc == 3){
main_loop = atoi(argv[1]);
handle = atoi(argv[2]);
}
ret = pthread_create(&pTestThread, NULL, (void *)testThread, NULL);
if (0 == ret){
if (handle == 0)
pthread_detach(pTestThread);
printf("====Thread creation okay!\n");
}else{
printf("====Thread creation error!\n");
return 0;
}
if (handle == 1)
{
printf("====pthread_join waiting\n");
pthread_join(pTestThread, (void **)&ret);
printf("====pthread_join ret %d\n", ret);
}
for (i=0; i < 20; i++)
{
printf("====Main loop %d\n", i);
sleep(1);
}
printf("====Main Exit\n");
return 0;
}
In this code, I have never seen the log of "====Main Exit" with a various combinations (argument 2nd and 3rd).
. Please, tell me why exiting of thread function causes main process
to be terminated?
Yes, In your thread function, you use "exit()", This function can "Terminates the process normally, performing the regular cleanup for terminating programs."
you can see http://www.cplusplus.com/reference/cstdlib/exit/ for more details:
Calling this function destroys all objects with static duration: A
program with multiple threads running shall not call exit (see
quick_exit for a similar function that does not affect static
objects).
So if you use pthread_exit instead of exit, you can see
====Main loop 18
====Main loop 19
====Main Exit
By the way,
ret = pthread_create(&pTestThread, NULL, (void *)testThread, NULL);
should be
ret = pthread_create(&pTestThread, NULL, testThread, NULL);
Looking at your code, ( assuming main_loop and handle are global )
if (main_loop == 1){ // Main thread will exit for if 1st argument is 1
exit(0);
}
else if (main_loop == 2) // Main thread will exit for if 1st argument is 2
{
sleep(10);
exit(0);
}
else if (main_loop == 3) // Main thread should not exit if 3
{
pthread_exit(NULL);
}
else if (main_loop == 4)
{
// Main thread should not exit if 3, delay however is 10 seconds
sleep(10);
pthread_exit(NULL);
}
// Interestingly for all other values main should run as usual
try running your binary as
./a.out 3 1
./a.out 4 1
./a.out 123 1
Note - 2nd argument is always 1, for execution to be sequenced.

waitpid() not waiting for child

I wrote a really basic shell and for some reason, when I use fork() and then waitpid() the parent process won't wait for the child.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/limits.h>
#include "LineParser.h"
#include <termios.h>
#define MAX_STR 2048
void execute(cmdLine *pCmdLine);
int main()
{
char isContinuing = 1;
char path[PATH_MAX];
char str[MAX_STR];
char something[MAX_STR+PATH_MAX];
cmdLine* cmd;
while(isContinuing)
{
getcwd(path, PATH_MAX);
printf("%s$ ", path);
fgets(str, MAX_STR, stdin);
if(!strncmp(str, "quit", strlen("quit")))
{
isContinuing = 0;
}
else
{
cmd = parseCmdLines(str);
if(cmd->arguments != '\0')
{
execute(cmd);
}
}
}
freeCmdLines(cmd);
return 0;
}
void execute(cmdLine *pCmdLine)
{
pid_t id = fork();
if(id == 0)
{
printf("I AM CHILD.\n");
if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments))
{
perror("execvp failed.\n");
exit(1);
}
exit(0);
}
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id);
printf("DONE WAITING\n");
}
LineParser header file is mine and it is fully working.
Now, for some reason, only the first command is working as expected,
let's assume an input "echo hi", the output is:
I AM PARENT.
WAITING FOR CHILD.
I AM CHILD.
DONE WAITING.
as expected and then it prints "hi" and the path, waiting for a command again.
For some reason, when I enter the SAME input "echo hi" the second time, the output is:
I AM PARENT.
WAITING FOR CHILD.
DONE WAITING.
$PATH$ //(WITHOUT WAITING FOR INPUT !!!)
I AM CHILD.
hi
//and here waiting for input//
Why does this happen?
There are several problems with your code:
not clearing malloc'd memory on every iteration through the while loop
putting a exit() statement in unreachable code
incorrect parameter list for the waitpid() function
unclear delination between parent code and child code in execute function
unused variable something
failed to check return value from fgets function
missing #include for sys/types.h
missing #include for sys/wait.h
IMO: the question should have included the definition of struct cmdLine
So here is a compilable version of your code. The compiler found many problems with the original code.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/limits.h>
//#include "LineParser.h"
#include <termios.h>
#include <sys/types.h>
#include <sys/wait.h> // prototype for waitpid()
//note: pid_t waitpid(pid_t pid, int *status, int options);
struct cmdLine
{
char ** arguments; // arguments[x] = ptr to an argument string
};
#define MAX_STR (2048)
#define MAX_PATH (256)
void execute(struct cmdLine *);
struct cmdLine * parseCmdLines( char * );
void freeCmdLines( struct cmdLine * );
int main()
{
char path[PATH_MAX];
char str[MAX_STR];
//char something[MAX_STR+PATH_MAX];
struct cmdLine* pCmd = NULL;
while(1)
{
getcwd(path, PATH_MAX);
printf("%s$ ", path);
if( NULL == fgets(str, MAX_STR, stdin) )
{
perror( "fgets failed" );
exit( EXIT_FAILURE );
}
// implied else
if(!strncmp(str, "quit", strlen("quit")))
{ // then strings equal
break; // exit while loop (and pgm)
}
// implied else input not equal 'quit'
pCmd = parseCmdLines(str);
if( (NULL != pCmd) && (NULL != pCmd->arguments) )
{ // then one or more arguments entered/parsed
execute(pCmd);
} // end if
freeCmdLines(pCmd); // free all strings memory, then free struct memory
pCmd = NULL; // cleanup
} // end while
return 0;
} // end function: main
void execute(struct cmdLine *pCmdLine)
{
int status = 0;
pid_t id = fork();
if(id == 0)
{ // then, child
printf("I AM CHILD.\n");
if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments))
{ // if no error then never gets here
perror("execvp failed.\n");
} // end if
}
else
{ // else, parent
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id, &status, 0);
printf("DONE WAITING\n");
} // end if
} // end function: execute
You invoke undefined behavior by calling the waitpid() function with the wrong number of arguments. Anything could happen.
This simplified variant of your code works fine for me:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main ()
{
int i;
for (i = 0; i < 3; i += 1)
{
pid_t id = fork();
if(id == 0)
{
char *argv[] = { "echo", "hi", NULL };
printf("I AM CHILD.\n");
execvp("echo", argv);
/* failed to exec */
perror("execvp failed.\n");
exit(1);
} else if (id < 0) {
perror("fork failed.\n");
exit(1);
}
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id, NULL, 0);
printf("DONE WAITING\n");
}
return 0;
}
Your call to waitpid(2) is wrong.
According to man 2 waitpid, it's:
pid_t waitpid(pid_t pid, int *status, int options);
You probably need to define an int and call it as:
waitpid(id, &status, 0);
or use the simpler version wait(2), which will work for any child:
wait(&status);
Your main problem is that you don’t let the compiler check your code. You should generally enable the compiler warnings and try to understand them.
$ gcc -Wall -Wextra -Werror -Os -c myshell.c
This is the minimum command line I use. When your code compiles with these settings, you have already eliminated a bunch of hard-to-find bugs in your code. Among these bugs is, as others already have mentioned, the call to waitpid.
Have a look at http://pubs.opengroup.org/onlinepubs/7908799/xsh/waitpid.html. The Open Group specification requires that you #include the two headers <sys/types.h> and <sys/wait.h> before using the waitpid function. Your program doesn’t do this.

Using Scanf() in child process executed via execv not working

I am executing a really simple program which takes input in integer from user using scanf. I execute this program as a child program via fork() and execv.The child program never takes input from user.Any help would be appreciated.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
pid_t childpid;
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
execv("child",NULL);
exit(1);
}
else
{
printf("Parent process is terminating...\n");
return 0;
}
}
and the child code is
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int temp;
printf("This is Child Process. Child is going to sleep for 5 seconds\n");
sleep(5);
printf("Please enter an integer to terminate the process ");
scanf("%d",&temp);
printf("You entered %d ",temp);
printf("Child terminated");
return 0;
}
OUTPUT
[#localhost cascading]$ ./cascading
Parent process is terminating...
[#localhost cascading]$ This is Child Process. Child is going to sleep for 5 seconds
Please enter an integer to terminate the process You entered 12435[#localhost cascading]$ ^C
[#localhost cascading]$
I am running the code in fedora installed on a virtual machine.Thanks
Once the parent process finishes, control is returned to shell; and stdin could be closed.
To retain child's access to stdin, you can let the parent wait until the child is done.
So, in your parent:
else {
printf("Parent process is terminating...\n");
wait(NULL);
return 0;
}
You need to wait for child process to be finished, please modify your code like this
if(childpid == 0)
{
execv("child",NULL);
exit(1);
}
else
{
wait(); //wait for child
printf("Parent process is terminating...\n");
return 0;
}

Resources