execvp and fork not working as expected - c

I have the following code:
for (loop=0;loop<2;loop++)
{
child_pid = fork();
if (child_pid == 0)
{
rc = execvp ("/usr/local/some_program", arguments);
}
}
I change the arguments passed to /usr/local/some_program based on the value of loop. I want the some_program to parallel-ly execute two instances. But i see that i first execute some_program once and only after it finishes that i get execute the second instance of some_program.
I not able to get them to run parallelly and independently.
Instead of fork, should i use pthreads?
The some_program that i am trying to execute is completely unrelated to the parent process.
Thanks

"I not able to get them to run parallelly and independently." - No. Both process will be executed in parallel. To check that create two programs like this-
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
printf("Pid= %d\n", getpid());
while(1);
}
Compile those 2 program's and make two executable files. Pass these 2 exe file names via command line arguments to main program and run that using system command.But your main program should be live.
for (loop=0;loop<2;loop++)
{
child_pid = fork();
if (child_pid == 0)
{
system(argv[loop+1]);
exit(0); // if you don't use exit your second exe file will be executed twice.
}
}
while(1);
Now type ps command in terminal and find the TTY name and run the main program. Open a new terminal and type
ps -e | grep pts/X // pts/X is main program running terminal name. it may pts/0 or pts/1 ...
Through this you can come to know that the two processes running parallelly or not.

Related

Profile a process via its child and kill the child afterwards

I am trying to figure out a way to profile in C a process via its child and after a moment the parent process kills its child to stop profiling. I am using perf to profile my application. perf is going to output its result in a file when killed. It looks like this in a bash script :
./run &
perf stat -o perf.data -p <pid_run> &
kill -9 <pid_perf>
What I have done so far :
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
static pid_t perf_id;
void start() {
char *filename="test_data";
char ppid_str[24];
pid_t pid = fork();
if (pid == 0){
pid_t ppid = getppid();
sprintf(ppid_str, "%d",ppid);
char *args[] = {"/usr/bin/perf", "stat","-p",ppid_str,"-o", filename, NULL};
execvp(args[0], args);
}
else {
perf_id = pid
}
}
void stop() {
kill(perf_id,SIGKILL);
}
I have an issue getting the output of perf.
This is an example of code that could run the parent process :
int main() {
start();
int a = 0;
a+=1;
stop();
// ... // There are other instructions after the stop
return 0;
}
I am not getting any output from perf when running this code. I have to kill the parent process to get an output.
If I put a sleep call before killing the child process, then the program will output an empty file.
EDIT :
stat argument is an example in my command, I want also to use the record argument
As mentioned by Zulan, if I use SIGINT instead of SIGKILL, I will get an output, but I can get one only if the main process sleeps for 1 second.
You should send a SIGINT instead of a SIGKILL in order to allow perf to shutdown cleanly and produce a valid output file. The synchronization between the perf child process and the main process will still be imperfect - so if the main process doesn't take significant time as in your example, it is easily possible that no output file is generated at all. This also affects the accuracy of collected data. With the setup of using perf as a child process rather than vice-versa, you cannot really improve it.
the problem is that perf attaches itself to the process and then waits for process termination to print counters. try adding for example the
-I msec
option to perf like -I 1000 to print counters every 1s.
changing your args to execvp to
char *args[] = {"/usr/bin/perf", "stat", "-p",ppid_str,"-o", filename, "-I", "1000", NULL};
and your inc to a loop of something like
while (a < 10) {
a += 1;
sleep(1);
}
while yield results although the file is not properly closed() in this approach.
I would create a small binary that execs perf with a timeout and gracefully closes the file and run that from the child.

Do *Unix shells call the pipe() function when encountering the "pipe character"? [duplicate]

I am working on a tiny shell(tsh) implemented in C(it's an assignment). One part of assignment belongs to PIPING. I have to pipe a command's output to another command. e.g:ls -l | sort
When I run the shell, every command that I execute on it, is processed by a child process that it spawns. After the child finishes the result is returned. For piping I wanted to implement a harcoded example first to check how it works. I wrote a method, that partially works. The problems is when I run the pipe command, after child process finishes, the whole program quits with it! Obviously I am not handling the child process signal properly(Method code below).
My Question:
How does process management with pipe() works? if i run a command ls -l | sort does it create a child process for ls -l and another process for sort ? From the piping examples that I have seen so far, only one process is created(fork()).
When the second command (sort from our example) is processed, how can i get its process ID?
EDIT: Also while running this code I get the result twice. don't know why it runs twice, there is no loop in there.
Here is my code:
pid_t pipeIt(void){
pid_t pid;
int pipefd[2];
if(pipe(pipefd)){
unix_error("pipe");
return -1;
}
if((pid = fork()) <0){
unix_error("fork");
return -1;
}
if(pid == 0){
close(pipefd[0]);
dup2(pipefd[1],1);
close(pipefd[1]);
if(execl("/bin/ls", "ls", (char *)NULL) < 0){
unix_error("/bin/ls");
return -1;
}// End of if command wasn't successful
}// End of pid == 0
else{
close(pipefd[1]);
dup2(pipefd[0],0);
close(pipefd[0]);
if(execl("/usr/bin/tr", "tr", "e", "f", (char *)NULL) < 0){
unix_error("/usr/bin/tr");
return -1;
}
}
return pid;
}// End of pipeIt
Yes, the shell must fork to exec each subprocess. Remember that when you call one of the execve() family of functions, it replaces the current process image with the exec'ed one. Your shell cannot continue to process further commands if it directly execs a subprocess, because thereafter it no longer exists (except as the subprocess).
To fix it, simply fork() again in the pid == 0 branch, and exec the ls command in that child. Remember to wait() for both (all) child processes if you don't mean the pipeline to be executed asynchronously.
Yes, you do need to call fork at least twice, once for each program in the pipeline. Remember that exec replaces the program image of the current process, so your shell stops existing the moment you start running sort or (tr).

C Program for shell: Execvp prints output and then segmentation fault occurs when executing a background process

I am writing a simple C program to create my own shell. It takes in input as commands and executes them. But when I try to execute a process in background( i.e. I fork a process from parent. The parent won't wait for the child process to finish, it just goes on to take more input commands while the child process runs in the background.) The execvp does execute the command but then gives a segmentation fault immediately.
Can you help me? I'll post my part of the code which I think is relevant. Let me know if you need to know anything more, i'll edit my question accordingly.
while(1){
pid = fork();
if(pid == 0)
executeCommand(info);
else
{
if(info->boolBackground ==1)
{
waitpid(pid , status , WNOHANG);
}
else
wait(NULL);
}
} //Info contains the command to be executed and it's arguments.
Here is me executeCommand function:
void executeCommand(parseInfo * info)
{
FILE *infile, *outfile;
struct commandType * com;
char * cmd;
int i , status;
cmd = (char*)malloc(1024);
strcpy(cmd , info->CommArray[0].command);
if(info->boolOutfile == 1)
{
outfile = fopen(info->outFile, "w");
dup2(fileno(outfile), 1);
}
if(info->boolInfile == 1)
{
infile = fopen(info->inFile, "r");
dup2(fileno(infile), 0);
}
status = execvp(cmd , info->CommArray[0].VarList); //VarList contains the arguments
if(status == -1){
printf("%s\n",strerror(errno));}
exit(0);
}
When I give an input command: ls &
(& means that ls should be executed in background.)
It forks a child process which executes ls and prints the list of files/directories in the directory and then gives segmentation fault. Can you spot the error? I tried running execvp in background with simply ls command. It also lead to a segmentation fault.
Yes, as Mark Plotnick pointed out in a comment, you'll need probably need &status. I'd use &info->status. Also, if you do detached jobs, you need to maintain a list of their info objects and do a waitpid loop on them:
forall (info in detached_detach_job_list) {
pid = waitpid(info->pid,&info->status,WNOHANG);
if (pid > 0) {
report_status(info);
remove_job_from_list(info);
}
}
Hopefully, the code frag you gave for your outer loop does something like this.
Also, I might not do "wait(NULL)" for a foreground. I'd treat it similarly to a detached job. Consider a case where a user does:det1 &
det2 &
...
det9000 &
run_long_30_minute_job
Because your shell is doing a hard wait on the foreground, it can't reap the detached jobs as they finish and you'll end up with zombie processes. Do the list/loop approach, just don't give user a prompt until the foreground completes (e.g. it's in the list, it's just the one with the background flag cleared). In other words, call the list something like child_list to denote all child processes, not just background. Put a sleep in the outer loop. Or, attach to SIGCHLD and do a single long sleep

Pipe and Process management

I am working on a tiny shell(tsh) implemented in C(it's an assignment). One part of assignment belongs to PIPING. I have to pipe a command's output to another command. e.g:ls -l | sort
When I run the shell, every command that I execute on it, is processed by a child process that it spawns. After the child finishes the result is returned. For piping I wanted to implement a harcoded example first to check how it works. I wrote a method, that partially works. The problems is when I run the pipe command, after child process finishes, the whole program quits with it! Obviously I am not handling the child process signal properly(Method code below).
My Question:
How does process management with pipe() works? if i run a command ls -l | sort does it create a child process for ls -l and another process for sort ? From the piping examples that I have seen so far, only one process is created(fork()).
When the second command (sort from our example) is processed, how can i get its process ID?
EDIT: Also while running this code I get the result twice. don't know why it runs twice, there is no loop in there.
Here is my code:
pid_t pipeIt(void){
pid_t pid;
int pipefd[2];
if(pipe(pipefd)){
unix_error("pipe");
return -1;
}
if((pid = fork()) <0){
unix_error("fork");
return -1;
}
if(pid == 0){
close(pipefd[0]);
dup2(pipefd[1],1);
close(pipefd[1]);
if(execl("/bin/ls", "ls", (char *)NULL) < 0){
unix_error("/bin/ls");
return -1;
}// End of if command wasn't successful
}// End of pid == 0
else{
close(pipefd[1]);
dup2(pipefd[0],0);
close(pipefd[0]);
if(execl("/usr/bin/tr", "tr", "e", "f", (char *)NULL) < 0){
unix_error("/usr/bin/tr");
return -1;
}
}
return pid;
}// End of pipeIt
Yes, the shell must fork to exec each subprocess. Remember that when you call one of the execve() family of functions, it replaces the current process image with the exec'ed one. Your shell cannot continue to process further commands if it directly execs a subprocess, because thereafter it no longer exists (except as the subprocess).
To fix it, simply fork() again in the pid == 0 branch, and exec the ls command in that child. Remember to wait() for both (all) child processes if you don't mean the pipeline to be executed asynchronously.
Yes, you do need to call fork at least twice, once for each program in the pipeline. Remember that exec replaces the program image of the current process, so your shell stops existing the moment you start running sort or (tr).

Execvp not being executed n times in a loop

Assume input is a pointer to array, which at each elements stores, "ls -l" at position 0, then cat helloworld.txt at position 1, and so forth, I wish to create the main parameter, which is ls, cat, pwd, and execute it. Essentially, what I am doing is I have a file with all those commands, I first store them in my input variable, which is declared as char *input[10]. Now I have what I need in that array, and I am able to extract the individual main commands, like ls, cat, and I wish to execute all of them.
For example,
if position 0 had ls -l, my first variable has ls and I wish to pass that to execvp and then position 1 might have cat sample.txt, now my variable first will be cat, and I pass that to execvp along with the entire cat sample.txt(which is input[i]), to execvp. For some strange reason, this is not working. How can I run all those commands in a loop in an execvp such that once it's done, all those commands have ran successfully. Here is my attempt, at the end of the first loop, I run an execvp, I expect that to finish, and then I extract further input, etc, etc.
Help me out.
for(i=0; i<lineCount; i++)
{
first = malloc(sizeof(char)*50);
for(j=0; j<strlen(input[i]); j++)
{
if(input[i][j]!=' ')
{
first[j]=input[i][j];
}
else
{
break;
}
}
execvp(first, input[i]);
}
I tried doing execp(first, input) but that didn't work either.
If you use execvp() once , the context of execution of the process that involved will be changed , except the pid of the process that called execvp , hence your loop won't work since once execvp() , there won't be any more iterations.
execvp() is mainly meant to be called by a child process , in your case for 'n' number of execvp() calls , there must have neen 'n' number of child processes forked,
Good Practices:
Using execl, execv, execle, execve, execlp, execvp , family of system calls , with child processes.
After the new process image is loaded to child , and after execution , collect the exit code of process launched , and perform any necessary error handling.
The child processes are now in a zombie state , the parent process must exexute wait()/waitpid() , and wait till all the child processes are terminated , and then exit.
-- Edit --
POC code for OP's reference
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
pid_t cpid;
int status = 0;
cpid = fork();
if (cpid == 0)
{
char *cmd[] = { "ls", "-l", (char *)0 };
int ret = execv ("/bin/ls", cmd);
}
wait(&status);
if(status < 0)
perror("Abnormal exit of program ls");
else
printf("Exit Status of ls is %d",status);
}
Here is what the opengroup exec manual says, in the first paragraph:
There shall be no return from a successful exec, because the calling
process image is overlaid by the new process image.
I suggest reading the opengroup fork manual, and using fork and exec in conjunction.
exec replaces the running process with the one you exec, and so it never returns on success because the process will be replaced.
If you want to run a bunch of processes, the simple way is to use a utility function like popen or system to run them. For complete control, use the usual UNIX fork/exec combo once for each command you want to run.

Resources