I have to show the elapsed time to run a command using pipes, so I use the gettimeofday function and pass the pointer through the pipe, but when I'm reading it in the father process I get a different result than expected. I'm supossed to get 1604626608037896 but instead I have this 94762421350317.
This is my code:
if (pipe(p) < 0)
exit(1);
pid=fork();
if (pid == -1){
printf("can't fork, error occured\n");
exit(EXIT_FAILURE);
}else if (pid == 0){
//This is the child I get the time
gettimeofday(¤t,NULL);
//I write it in the pipe, if I print the time here i get the result I want
write(p[1], ¤t, sizeof(current));
close(p[1]);
//then I execute the command
}else{
//this is the parent
if (waitpid(pid, &status, 0) > 0){
close(p[1]);
struct timeval inicio;
//Here is the problem I think, once I tried to read it I get a random number
read(p[0], &inicio, sizeof(inicio));
printf(": %ld,%ld\n", inicio.tv_sec,inicio.tv_usec);
}else{
printf("waitpid() failed\n");
}
exit(0);
}
I believe you are expecting that the if block runs in the child process and else block is running in parent process and the fork is called before the code segment. In that case the p in two process are different for two process and they are not connected.
Your read call if throwing a error. Can you check the return value at of the read system call?
The modified code snipped should looks like
if (pipe(p) < 0)
exit(1);
if (fork() < 0)
exit(1);
if (pid == 0){
//I get the time
gettimeofday(¤t,NULL);
//I write it in the pipe, if I print the time here i get the result I want
if (write(p[1], ¤t, sizeof(current)) < 0) {
perror("write");
exit(1);
}
close(p[1]);
//then I execute the command
}else{
if (waitpid(pid, &status, 0) > 0){
close(p[1]);
struct timeval inicio;
//Here is the problem I think, once I tried to read it I get a random number
if (read(p[0], &inicio, sizeof(inicio)) < 0) {
perror("read");
exit(1);
}
printf(": %ld,%ld\n", inicio.tv_sec,inicio.tv_usec);
}else{
printf("waitpid() failed\n");
}
exit(0);
}
Related
For some unknown reason, when I'm executing piped commands in my shell program, they're only outputting once I exit the program, anyone see why?
Code:
int execCmdsPiped(char **cmds, char **pipedCmds){
// 0 is read end, 1 is write end
int pipefd[2];
pid_t pid1, pid2;
if (pipe(pipefd) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
pid1 = fork();
if (pid1 < 0) {
fprintf(stderr, "Fork Failure");
}
if (pid1 == 0) {
// Child 1 executing..
// It only needs to write at the write end
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
if (execvp(pipedCmds[0], pipedCmds) < 0) {
printf("\nCouldn't execute command 1: %s\n", *pipedCmds);
exit(0);
}
} else {
// Parent executing
pid2 = fork();
if (pid2 < 0) {
fprintf(stderr, "Fork Failure");
exit(0);
}
// Child 2 executing..
// It only needs to read at the read end
if (pid2 == 0) {
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
if (execvp(cmds[0], cmds) < 0) {
//printf("\nCouldn't execute command 2...");
printf("\nCouldn't execute command 2: %s\n", *cmds);
exit(0);
}
} else {
// parent executing, waiting for two children
wait(NULL);
}
}
}
Output:
In this example of the output, I have used "ls | sort -r" as the example, another important note is that my program is designed to only handle one pipe, I'm not supporting multi-piped commands. But with all that in mind, where am I going wrong, and what should I do to fix it so that it's outputting within the shell, not outside it. Many thanks in advance for any and all advice and help given.
The reason would be your parent process file descriptors are not closed yet. When you wait for the second command to terminate, it hangs because the writing end is not closed so it wait until either the writing end is closed, or new data is available to read.
Try closing both pipefd[0] and pipefd[1] before waiting for process to terminate.
Also note that wait(NULL); will immediately return when one process has terminated, you would need a second one as to not generate zombies if your process still runs after that.
I am trying to write a simple shell program, but have a small bug, which I can't seem to solve.
The program should be capable of launching a background process, but it fails to do so properly. It seems to work at first (program launches & the shell is still responsible) but fails at the second command.
In other words what happens is
launch some background process (browser) - works (launches and keeps working)
launch some regular process - works (lunches & finishes)
launch another process - doesn't work. The shell isn't responsive and waits until the background process is over.
Removing the following line:
waitpid(pid,NULL,0);
Solves this issue, but now all programs are 'background' (shell won't wait for anything to finish).
This is the complete function:
int launchprog(int background, char** arglist){
/* create a background process*/
if(background == 1){
pid_t pid = fork();
if(pid == 0){
/* child*/
arglist[-1] = NULL;
if (execvp(arglist[0], arglist) == -1) {
perror("Error in execvp, cannot init child process");
}
exit(1);
} else if (pid < 0) {
perror("Forking error");
exit(1);
}
return 1;
}
/* create a simple process*/
printf("shalom, %d,%d\n", background,getpid());
pid_t pid = fork();
if (pid == 0) {
/* child*/
struct sigaction saint;
saint.sa_handler = &int_signal_handle_exit;
sigemptyset(&saint.sa_mask);
saint.sa_flags = 0;
if (sigaction(SIGINT, &saint, 0) == -1) {
perror("Sigaction Error");
exit(1);
}
if (execvp(arglist[0], arglist) == -1) {
perror("Error in execvp, cannot init child process");
}
exit(1);
}
else if (pid < 0) {
perror("Forking error");
exit(1);
} else {
if (background == 0){ /* this should always be true*/
waitpid(pid,NULL,0);
}
}
return 1;
}
So I have this program where the initial process sends numbers to the child, then the child performs certain operations with numbers and sends them to the next child...
My problem is that where the program has to send the numbers starting from two (2), the first number the child gets is 3. What could the problem be?
Here is my code:
void start(int num_of_nums){
if (num_of_nums <= 0) return;
int pipefd[2];
pid_t cpid;
int pipe_res = pipe(pipefd);
if (pipe_res == -1) {
printf("pipe error in start\n");
perror("pipe error");
exit(EXIT_FAILURE);
}
//create a new process
cpid = fork();
if (cpid == -1) {
printf("fork error in start\n");
perror("fork error");
exit(EXIT_FAILURE);
}
if (cpid == 0) { // child
printf("child in start\n");
close(pipefd[1]); // close write end
int num_from_parent = pipefd[0]; //where the number is read
printf("num from parent is %d\n", num_from_parent); //prints out 3...
filter(num_from_parent);
} else { // parent
printf("parent in start\n");
close(pipefd[0]); // close read end
for (int i = 2; i <= num_of_nums + 1; i++){
write(pipefd[1], &i, sizeof(int)); //WHERE THE NUMBERS ARE SENT
}
close(pipefd[1]);
}
}
Help would be much appreciated...
I am using pipe fork and exec, to implement a generic pipe for any two shell programs. I am specifically using ls | grep to test it. It works, the data gets copied over to grep, grep searches for matches and then outputs them to stdout. However after that the program just hangs.
This is my code that is executed when a pipe is detected. I fork, and then fork again because I wish to have the parent process of the first fork continue to run after the exec calls. I believe due to debug code that after the exec() call that executes grep is made that nothing is happening.
if(pipeFlag == 1){
pipe(fd);
PID = fork();
if (PID == 0){//child process
fPID = fork();
if(fPID == 0){//child of child
printf("in child of child\n");
dup2(fd[1], 1);
execvp(command, argv);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(fPID > 0){//parent of 2nd child
printf("in parent of 2nd child\n");
dup2(fd[0], 0);
execvp(command1, argv1);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
if(PID > 0){//parent
wait(PID, 0, 0);
printf("in outer parent\n");
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
Below is my solution to the problem. I'm not sure if it's a permanent solution. I'm not even 100% sure if my reasoning for why this works and the previous code did not isn't. All I did was switch the command that is waiting for input from the pipe(grep) to the parent process, and the command writing output to the pipe(ls) to the child process.
My reasoning for why this works is thus: I was testing with ls | grep, ls was finished writing to the pipe before grep's child process ever got set up, and therefore never closed the pipe and grep never received EOF. By changing their position grep was ready and waiting for ls to write by the time the process running ls is set up. I believe that this is a very imperfect fix, so for anyone who reads this in the future, I hope you can provide a better answer. There are a number of conditions I can think of where this could still mess up, if my reasoning for why it works is correct.
if(pipeFlag == 1){
pipe(fd);
PID = fork();
if (PID == 0){//child process
fPID = fork();
if(fPID == 0){//child of child
printf("in child of child\n");
dup2(fd[0], 0);
execvp(command1, argv1);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(fPID > 0){//parent of 2nd child
printf("in parent of 2nd child\n");
dup2(fd[1], 1);
execvp(command, argv);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
if(PID > 0){//parent
wait(PID, 0, 0);
printf("in outer parent\n");
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
Learning to use the fork() command and how to pipe data between a parent and it's children. I am currently trying to write a simple program to test how the fork and pipe functions work. My problem seems to be the correct use/placement of the wait function. I want the parent to wait for both of its children to finish processing. Here is the code I have so far:
int main(void)
{
int n, fd1[2], fd2[2];
pid_t pid;
char line[100];
if (pipe(fd1) < 0 || pipe(fd2) < 0)
{
printf("Pipe error\n");
return 1;
}
// create the first child
pid = fork();
if (pid < 0)
printf("Fork Error\n");
else if (pid == 0) // child segment
{
close(fd1[1]); // close write end
read(fd1[0], line, 17); // read from pipe
printf("Child reads the message: %s", line);
return 0;
}
else // parent segment
{
close(fd1[0]); // close read end
write(fd1[1], "\nHello 1st World\n", 17); // write to pipe
// fork a second child
pid = fork();
if (pid < 0 )
printf("Fork Error\n");
else if (pid == 0) // child gets return value 0 and executes this block
// this code is processed by the child process only
{
close(fd2[1]); // close write end
read(fd2[0], line, 17); // read from pipe
printf("\nChild reads the message: %s", line);
}
else
{
close(fd2[0]); // close read end
write(fd2[1], "\nHello 2nd World\n", 17); // write to pipe
if (wait(0) != pid)
printf("Wait error\n");
}
if (wait(0) != pid)
printf("Wait error\n");
}
// code executed by both parent and child
return 0;
} // end main
Currently my output looks something along the lines of:
./fork2
Child reads the message: Hello 1st World
Wait error
Child reads the message: Hello 2nd World
Wait error
Where is the appropriate place to make the parent wait?
Thanks,
Tomek
That seems mostly ok (I didn't run it, mind you). Your logic error is in assuming that the children will end in some particular order; don't check the results of wait(0) against a particular pid unless you're sure you know which one you're going to get back!
Edit:
I ran your program; you do have at least one bug, your second child process calls wait(), which you probably didn't want to do. I recommend breaking some of your code out into functions, so you can more clearly see the order of operations you're performing without all the clutter.
i think its better to use something like this, in order to wait for all the childrens.
int stat;
while (wait(&stat) > 0)
{}