Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

Unix pipes

Name: noob 2009-11-07 21:00

How do you normally work with pipes in unix programming? Do you have one parent process that spawns many children and then keeps track of them or could you somehow make a nice chain where the child process fork() again and again and then wait() for each other or something?

Yeah its an assignment, and i have already solved it in an ugly way... Im just curious how you normally do this. Btw. one of the programs i have in my pipe-chain is less, and it wont work any other way than if i do a exec() in the parent process, but then i cant keep track of i'ts exit status. Can i somehow get it into the foreground of the console while still having it as a child to my parent process?

Name: Anonymous 2009-11-07 21:03

I don't. Pipes are fail that enter the kernel with every read/write, and require the code to serialize and deserialize data. Try to send closures over pipes while failing as little as possible. I use threads, possibly message-passing.

Name: noob 2009-11-07 21:05

I might consider using domain sockets or something if i had a choice, but i don't.

Name: Anonymous 2009-11-07 21:10

popen()
or a
int fd[2];
pipe(&fd);
if(fork() == 0){
   close(fd[0]);
   dup2(0,fd[1]);
   exec(whatever_program,...);
}
else{
   close(fd[1]);
   dup2(1,fd[0]);
   wait();
}


wait.... what was the question again? i kinda got distracted.
eh, i don't really care.
DISCLAIMER: code will not compile and is probably incorrect due to me not giving a shit

Name: Anonymous 2009-11-07 21:10

UDS suck as much. Make a data serializer or something. Just don't make an ad-hoc serialization protocol that only works for one protocol message type.

Name: Anonymous 2009-11-07 21:12

>>1
try duping parent's stdin/out to the pipes of the child.. man dup and dup2 iirc..

Name: Anonymous 2009-11-07 21:13

controller/parent process that does while(wait())

Name: Anonymous 2009-11-07 21:22

Even if i dup the parents sdin and stdout to it before i fork somehow won't work. But well, i could of course let less execute in the parent process and then make a child that waits for everything, but shouldn't some someone wait for that child then?

Name: noob 2009-11-07 21:24

Ah, well. Figure something out. =)

Name: Anonymous 2009-11-07 21:25

>>8
orphaned children are adopted by init, which then prevents them from turning into zombies.
or so i've been told

Name: Anonymous 2009-11-07 21:30

>>10
what about orphaned zombies?

Name: Anonymous 2009-11-07 21:32

>>8
This sounds like lies.
yes|perl -e'fork ? wait : exec "less"'
…works exactly as expected.  Have you considered that you haven't tried it and are lying?

Name: noob 2009-11-07 21:41

>>12

Open sauce...
Btw. As i said this, is a  assignment in a OS course im taking,
so this stuff is not really usefull for much.

As you might also se im currently not doing any wait() since im not sure how to implement that in this crappy solution.

The main code:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include "digenv_helper.h"

int setup_piping( char* greparg )
{
  int to_printenv[2] = { -1, -1 };
  int from_printenv[2] = { -1, -1 };
  int from_grep[2] = { -1, -1 };
  int from_sort[2] = { -1, -1 };
  char* cmd_arg1[] = { "printenv", NULL };
  char* cmd_arg2[] = { "grep", greparg, NULL };
  char* cmd_arg3[] = { "sort", NULL };
  char* cmd_arg4[] = { "less", NULL };
  create_pipe( to_printenv );
  create_pipe( from_printenv );
  create_pipe( from_grep );
  create_pipe( from_sort );
  pipe_exec( cmd_arg1, to_printenv, from_printenv);
  pipe_exec( cmd_arg2, from_printenv, from_grep );
  pipe_exec( cmd_arg3, from_grep, from_sort );

  /* The end of the last pipe is stdin  */
  dup2( from_sort[0], 0 );
  close( to_printenv[0] );
 
  /* LESS */
  execvp( cmd_arg4[0], cmd_arg4 );
 
  return 0;
}

int main( int argc, char** argv )
{
  char* greparg;
  if( argc > 1 )
    greparg = argv[1];
  else
    greparg = "";
  if( setup_piping( greparg ) < 0 )
    fprintf( stderr, "The pipes are no more..." );
  return 0;
}

------------------------------------------
The helper module:

#include "digenv_helper.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>


/** Prints an error message based on the value of errno and exits.
 **  @param src Description of the action that failed.
 **/
void error(char* src)
{
  fprintf(stderr, "%s failed with error: %s \n", src, strerror(errno));
  exit(1);
}

/** Waits for a process to exit and prints a message if exitstatus was non-zero.
 **/
void waitfor(int pid) {
  int status;
  if (waitpid(pid, &status, 0) == -1) error("waitpid");
  if (status != 0) {
    fprintf(stderr, "process with pid %d returned exitstatus: %d", pid, status);
    exit(1);
  }
}

/**
 ** Spawn a new daemon and connect pipes to it's stdin and stdout.
 **
 ** @param stdin The child's new stdin.
 ** @param stdout The child's new stdout.
 ** @return If all went well the return in the parent process is the pid \\
 ** of the child and zero in the child process. If something went wrong \\
 ** the value returned is -1. This is the value returned from fork().
 **/
int spawn( int* to_pipe, int* from_pipe )
{
  int pid = fork();
  if( pid == 0 )
  { /* This process is the child */
    /* Attach the new stdout/pipe */
    if( from_pipe[0] != 1 )
    {
      dup2( from_pipe[1], 1 );
      close( from_pipe[1] );
    }
    /* Attach the new stdin/pipe */
    if( to_pipe[1] != 0 )
    {
      dup2( to_pipe[0], 0 );
      close( to_pipe[0] );
    }
    close( to_pipe[1] );
    close( from_pipe[0] );
  } else { /* Parent */
    /* Close the unused file descriptors */
    close( to_pipe[0] );
    close( from_pipe[1] );
  }
  return pid;
}


/**
 ** Create a pipe.
 **
 ** @param fd An array of two integers. The first element will be the file descriptor \\
 ** for the read end of the pipe and the second will be for the write end.
 ** @return Returns zero if successful and -1 otherwise.
 **/
void create_pipe( int* fd )
{
  fd[0] = -1;
  fd[1] = -1;
 
  if(pipe( fd ) == -1) error("pipe");
}


/**
 ** Run a process as daemon with stdin and stdout redirected. Uses the file descriptors in to_pipe and from_pipe.
 **
 ** @param cmd_arg The command and arguments as an array of strings. \\
    The first element is the command and the last a NULL pointer.
 ** @param to_pipe The write end of the child's standard input for cmd.
 ** @param from_pipe The read end of the child's standard output for cmd.
 ** @return Returns the child's pid to the parent, zero to the child and -1 if something went wrong.
 **/
int pipe_exec( char** cmd_arg, int* to_pipe, int* from_pipe )
{
  int pid = 0;
  if( pid = spawn( to_pipe, from_pipe ), pid < 0 )
  {
    error("pipe_exec");
  } else if( pid == 0 ) { /* This block is run in the child only. */
    execvp( cmd_arg[0], cmd_arg );
  }
  return pid;
}

Name: Anonymous 2009-11-07 21:50

here's an idea.
set up a signal handler that waits for SIGCHLD and then calls wait.
something like:

main()
{
   signal(SIGCHLD, handler);
   //rest of program
}

void handler(int x)
{
   wait();
}

Name: noob 2009-11-07 21:57

>14
Much appreciated, thanks.

Name: Anonymous 2009-11-07 22:15

>>15
i just wrote a small program to test it:

#include<stdio.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>

void handler(int);

unsigned int children = 0;

main()
{
   signal(SIGCHLD, handler);

   int i;
   pid_t pid;
   for(i = 0; i < 5; ++i){
      pid = fork();
      if(pid == 0){
         return;
      }
      else{
          children++;
      }
   }
   while(children > 0);
   return;
}

void handler(int x)
{
   int status;
   pid_t pid;
   while((pid = waitpid(-1, &status, WNOHANG)) != -1){
      printf("child %d\n", pid);
      children--;
   }
   return;
}


note that the children variable is only required for the while loop to know when to stop at the end. that part of the code could be implemented much more elegantly

Name: Anonymous 2009-11-07 22:28

>>16
while((pid = waitpid(-1, &status, WNOHANG)) != -1)
Should be:
while((pid = waitpid(-1, &status, WNOHANG)) > 0)

Name: noob 2009-11-07 22:28

>>16
Cute. Then less taking over the parent process won't be a problem since i can do wait and error handling in the signal handler. To be honest, i have never used a singal handler before (since i'm new at this), so i didn't think of using one.

Thanks for the explanatory code snipplet. =).
I'm gonna go to bed now. It's 04:28 in the morning over here by now.

Name: Anonymous 2009-11-08 6:08

Is this for COMP2310?

Name: Anonymous 2009-11-08 7:29

I am the author of an EXPERT NCURSES APPLICATION FRAMEWORK that fork()s all over the place and doesn't afraid of anything. But I don't think I can help you because the children don't want to go to the foreground of the console.

Name: Anonymous 2009-11-08 7:31

My unix pipe is quite huge if you catch my drift.

Name: Anonymous 2009-11-08 8:32

>>21
too bad it's got nothing to write too!!

Name: Anonymous 2009-11-08 19:24

>>22
I'll have you know that my pipe writes to my parent process

Name: noob 2009-11-09 4:49

>>16
Fuck, this method dosen't work with my code since none of the children will die before less dies.
And then, the singal handler is removed as well.
So I've got to set up another process that works as a handler, or just redo this from the start and do it right, somehow...

Name: Anonymous 2009-11-09 4:56

>>24
then just use the
if(fork() == 0){
   //child code
}
else{
   wait();
}

method.
simple but effective.

Name: noob 2009-11-09 6:56

>>25
Well, less is last in the pipe-chain so I can't do a wait before doing exec on less because none of the children will die before less has died.

Maybe i should just skip doing wait at all, is that cool? Isn't there a risk processes will become zombies and crap then?

Name: Anonymous 2009-11-09 7:02

>>26
nope.
as said earlier in the thread, orphaned child processes are adopted by init, which then does the whole wait thing for them.

Name: Anonymous 2009-11-09 8:16

>>26
What the fuck does being ``last in the chain'' have to do with anything?  Who cares what order anyone dies in?  This is ridiculous.

Name: noob 2009-11-10 20:39

>>28
>>8
>>6

Well i did it all wrong, i was solving my "problem" by replacing stdin with the last pipe and then doing an exec on less.
However, i found out last night that if you just setup the pipes correctly which i failed to do, and then forkexec less as a child and have the parent wait for it everything works fine.
However, if you don't do a wait, it won't work since less will exit as soon as the parent dies. It was really that simple, i just couldn't get every thing right at the same time.

/Thread

Name: Anonymous 2011-02-03 3:24

Name: Anonymous 2011-02-03 3:55

Name: Anonymous 2013-08-31 13:41


Can we ban all of the infidels already, or at least make a rule that they have to convert to the one true religion? It's bad enough having them whine about not sinning all the time, but I also genuinely think that when their lives are filled with the word of the Prophet Muhammad blessed be his name that they will be happy lives.

Name: Anonymous 2013-08-31 14:26


 looked in the mirror, and my skin burned away revealing my skull in the reflection! I looked away, and then back at the mirror, and my head was an ass! Not a HEE HAW ass, but a tush! You know what I'm saying? And there was a lit cig in the crack. What's going on, lounge?

Name: Anonymous 2013-08-31 15:11


 Translation of Towelket 1 is coming along smoothly, expect to see a partial translation in about 2~3 days!

Don't change these.
Name: Email:
Entire Thread Thread List