help w/ pipes
Web Server forum
Back To The Forum Home!Search!Private Messaging System

Web Server Talk Web Server Talk > Unix and Linux reviews > Free Unix support > Unix Programming > help w/ pipes




Pages (3): [1] 2 3 »   Last Thread   Next Thread Next
  Show Printable Version Email this Page Subscribe to this Thread      Post New Thread    Post A Reply      

    help w/ pipes  
Adam Bozanich


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:27 PM

Hi all.  I am trying to write a simple shell.  I am running into
problems understanding how to use pipe() to implement '|'.  I pulled out
the section of code that is giving me trouble and made a little example.
Maybe somebody can tell me what's wrong?

I loop through the commands to be run starting at the end.  I pipe() and
then dup2() the 'write' end of the pipe w/ stdout in the parent, and
dup2() the 'read' end of the pipe w/ stdin in the child.  I thought
that this would leave STDOUT going into the pipe for the final command,
but it is not working.

Also, I was running into some race conditions I believe... how would
you wait for _all_ of the processes to finish, rather than just one?

TIA

-Adam Bozanich

/* example_pipe.c */
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<errno.h>

#define DIE(str) { fprintf(stderr,"%s\n",str); exit(errno); }

#define STDIN_FILENO  0
#define READFD        0
#define STDOUT_FILENO 1
#define WRITEFD       1

int main()
{
char  *args[] = { "/bin/ls" , "/bin/wc" };
int    count = 2;
do_procs(count,args);
}

int do_procs(int proc_count,char** procs)
{
int   fd[2];
int   i;
pid_t pid;

/*
* Loop through all processes from end until second in line
*/

for( i = proc_count - 1 ; i > 0 ; i-- )
{
if(pipe(fd)<0)
DIE("pipe()")

if((pid = fork())<0)
DIE("fork()")

else if(pid > 0) /* parent */
{
if(dup2( fd[ WRITEFD ] , STDOUT_FILENO )<0)
DIE("dup2");

close(fd[ READFD  ]);
close(fd[ WRITEFD ]);
}
else            /* child */
{
if(dup2( fd[ READFD ] , STDIN_FILENO )<0)
DIE("dup2");

close(fd[ WRITEFD ]);
close(fd[ READFD  ]);

execlp(procs[i],procs[i],NULL);
}
}

/*
* Now we execute the last one, close all files, and wait...
*/

if((pid = fork())<0)
DIE("fork()")

else if(pid == 0) /* child */
{
execlp(procs[0],procs[0],NULL);
}
else
{
wait(NULL);
}
return(0);
}






[ Post a follow-up to this message ]



    Re: help w/ pipes  
Adam Bozanich


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:27 PM


On Mon, 1 Dec 2003, Adam Bozanich wrote:
quote:
> /* example_pipe.c */ > char *args[] = { "/bin/ls" , "/bin/wc" };
Damm, I've got to get som sleep. I'm Really sorry if anybody wasted time on this one, my wc binary is in /usr/bin/. It seems to be working now w/ "/usr/bin/wc". I guess I've got to look for a different problem (any hints on waiting for all of the processes would be great). -Adam




[ Post a follow-up to this message ]



    Re: help w/ pipes  
inf


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:27 PM

Adam Bozanich wrote:
quote:
> On Mon, 1 Dec 2003, Adam Bozanich wrote: > > > > > Damm, I've got to get som sleep. > > I'm Really sorry if anybody wasted time on this one, my wc binary is > in /usr/bin/. It seems to be working now w/ "/usr/bin/wc". > > I guess I've got to look for a different problem (any hints on waiting for > all of the processes would be great). > > -Adam > >
the way i handled this in my implementation was to: a)install a signal handler in the parent for SIGCHLD b)fork off all children, and then call wait(pid) after forking the last child in the pipeline or instead of calling wait you could probably just call pause() instead since the wait call will be interrupted by SIGCHLD.




[ Post a follow-up to this message ]



    Re: help w/ pipes  
Adam Bozanich


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:29 PM

On Tue, 2 Dec 2003, inf wrote:
quote:
> > the way i handled this in my implementation was to: > a)install a signal handler in the parent for SIGCHLD > b)fork off all children, and then call wait(pid) after forking the last > child in the pipeline > or instead of calling wait you could probably just call pause() instead > since the wait call will be interrupted by SIGCHLD. >
Thanks. I tried that but can not get it to work. I think that it might be because I have more levels of forks(), but I tried it exactly like you sa id and I get pretty much the same result. Does SIGCHLD get raised when the child of a child exits? If not, how can I deal with something like this: if(fork==0) { while(more than 1 process left) { if(fork()==0) { exec a process } } exec the last process } Here's my example code again. It works, but I don't think that it's waiting for _all_ of the children. Any suggestions appreciated. Thanks -Adam #include<stdio.h> #include<sys/types.h> #include<signal.h> #include<sys/wait.h> #include<errno.h> #define DIE(str) { fprintf(stderr,"%s\n",str); exit(errno); } #define STDIN_FILENO 0 #define READFD 0 #define STDOUT_FILENO 1 #define WRITEFD 1 #define Dup2(a,b) ( dup2(a,b) >= 0 ) ? : ( perror("dup2()"), exit(errno) ) #define Pipe(fd) ( pipe(fd) >= 0 ) ? : ( perror("pipe()"), exit(errno) ) #define Signal(a,b) ( signal(a,b) >= 0 ) ? : ( perror("pipe()"), exit(errno) ) static void sig_chld(); static int child_count; int doProcs(int,char**); /* what I'm testing */ int main(int argc, char **argv) { char *args[] = { "/bin/ls" , "/usr/bin/wc" , "/usr/bin/wc" }; int count = 3; child_count = count; Signal(SIGCHLD,sig_chld); if(doProcs(count,args)<0) DIE("doProcs()") exit(0); } int doProcs(int proc_count,char** procs) { int fd[2]; int i; int ret; pid_t pid; if(fork()==0) { for( i = proc_count - 1 ; i > 0 ; i-- ) { Pipe(fd); if(fork() > 0) /* parent */ { /* Signal(SIGCHLD,sig_chld); */ Dup2( fd[ WRITEFD ] , STDOUT_FILENO ); close(fd[ READFD ]); close(fd[ WRITEFD ]); } else /* child */ { Dup2( fd[ READFD ] , STDIN_FILENO ); close(fd[ WRITEFD ]); close(fd[ READFD ]); execlp(procs[i],procs[i],NULL); exit(errno); } } execlp(procs[0],procs[0],NULL); exit(errno); } else { /* waitpid(0,&ret,0); */ while(child_count>0) pause(); } return(0); } static void sig_chld(int n) { int ret; fprintf(stderr,"Caught SIGCHLD\nchild_count= %d\n",child_count--); wait(&ret); fprintf(stderr,"Child died with %d\n",ret >> 8); return; }




[ Post a follow-up to this message ]



    Re: help w/ pipes  
Barry Margolin


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:29 PM

In article
<Pine.HPX.4.44.0312071239380.17338-100000@hills.ccsf.cc.ca.us>,
Adam Bozanich <abozan01@ccsf.edu> wrote:
quote:
> On Tue, 2 Dec 2003, inf wrote: > > > Thanks. I tried that but can not get it to work. I think that it might > be because I have more levels of forks(), but I tried it exactly like you said > and I get pretty much the same result. > > Does SIGCHLD get raised when the child of a child exits?
No, you only get a signal when one of your direct childred exits. If a grandchild exits, the signal will go to the child who spawned it, not to you (and if that child has already exited, the grandchild is repatriated to init, who will get the signal).
quote:
> > If not, how can I deal with something like this: > > if(fork==0) > { > while(more than 1 process left) > { > if(fork()==0) > { > exec a process > } > } > > exec the last process > }
Have the original process fork a child for each program in the pipeline, and then go into a loop calling wait() until it returns -1 with errno == ECHILD. -- Barry Margolin, barmar@alum.mit.edu Woburn, MA




[ Post a follow-up to this message ]



    Re: help w/ pipes  
inf


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:30 PM

believe i found the problem, here:
quote:
> else if(pid > 0) /* parent */ > { > if(dup2( fd[ WRITEFD ] , STDOUT_FILENO )<0) > DIE("dup2"); > > close(fd[ READFD ]); //THIS RIGHT IN HERE ********** > close(fd[ WRITEFD ]); > } > else /* child */ > { > if(dup2( fd[ READFD ] , STDIN_FILENO )<0) > DIE("dup2"); > > close(fd[ WRITEFD ]); > close(fd[ READFD ]); > > execlp(procs[i],procs[i],NULL); > } > }
i dont think you should be closing the read end of that pipe. the read end of that pipe is what the next process should be dup2'ing to its standard input. the writefd should remain closed however for teh 2nd process to correctly read EOF on stdin. try commenting out that line and see how it goes. hmm actually now that i look at it there are more problems that just that. the child needs to dup2'ing its output to the pipe and possibly dup2'ing its input if it is not the first child. in your setup now, the first child wiill be dup2'ing a pipe to its stdin. teh duplicating of descriptors should be done only in the child, that is how i managed to do it at least. maybe having a look at the shell i wrote may help, www.1nfamus.netfirms.com its about halfway down. it only handles one pipe, but does handle both redirection operators( '<' && '>'). hth Adam Bozanich wrote:
quote:
> Hi all. I am trying to write a simple shell. I am running into > problems understanding how to use pipe() to implement '|'. I pulled out > the section of code that is giving me trouble and made a little example. > Maybe somebody can tell me what's wrong? > > I loop through the commands to be run starting at the end. I pipe() and > then dup2() the 'write' end of the pipe w/ stdout in the parent, and > dup2() the 'read' end of the pipe w/ stdin in the child. I thought > that this would leave STDOUT going into the pipe for the final command, > but it is not working. > > Also, I was running into some race conditions I believe... how would > you wait for _all_ of the processes to finish, rather than just one? > > TIA > > -Adam Bozanich > > /* example_pipe.c */ > #include<stdio.h> > #include<sys/types.h> > #include<sys/wait.h> > #include<errno.h> > > #define DIE(str) { fprintf(stderr,"%s\n",str); exit(errno); } > > #define STDIN_FILENO 0 > #define READFD 0 > #define STDOUT_FILENO 1 > #define WRITEFD 1 > > int main() > { > char *args[] = { "/bin/ls" , "/bin/wc" }; > int count = 2; > do_procs(count,args); > } > > int do_procs(int proc_count,char** procs) > { > int fd[2]; > int i; > pid_t pid; > > /* > * Loop through all processes from end until second in line > */ > > for( i = proc_count - 1 ; i > 0 ; i-- ) > { > if(pipe(fd)<0) > DIE("pipe()") > > if((pid = fork())<0) > DIE("fork()") > > else if(pid > 0) /* parent */ > { > if(dup2( fd[ WRITEFD ] , STDOUT_FILENO )<0) > DIE("dup2"); > > close(fd[ READFD ]); > close(fd[ WRITEFD ]); > } > else /* child */ > { > if(dup2( fd[ READFD ] , STDIN_FILENO )<0) > DIE("dup2"); > > close(fd[ WRITEFD ]); > close(fd[ READFD ]); > > execlp(procs[i],procs[i],NULL); > } > } > > /* > * Now we execute the last one, close all files, and wait... > */ > > if((pid = fork())<0) > DIE("fork()") > > else if(pid == 0) /* child */ > { > execlp(procs[0],procs[0],NULL); > } > else > { > wait(NULL); > } > return(0); > } >




[ Post a follow-up to this message ]



    Re: help w/ pipes  
inf


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:30 PM

just one more thing, the way i found out how bash does stuff is by using
one of the greatest debugging t00lz
ever, strace.  you can find exactly what systems calls are being made,
and the exact order of them as well will tell you how to handle the
pipes.  man strace for more info 






[ Post a follow-up to this message ]



    Re: help w/ pipes  
Adam Bozanich


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:31 PM



On Wed, 10 Dec 2003, inf wrote:
quote:
> just one more thing, the way i found out how bash does stuff is by using > one of the greatest debugging t00lz > ever, strace. you can find exactly what systems calls are being made, > and the exact order of them as well will tell you how to handle the > pipes. man strace for more info
Thanks inf. I checked out strace, but I'm running FreeBSD and they require linux emulation to run strace. I think it may be the same as a native program 'ktrace', but I haven't had time to look into it. I finally got a chance to work on this project some more and got a working pipeline example now. Thanks to all who replied. I am having a problem with my macros on my schools server (HPUX), maybe someone can tell me the correct syntax for the Dup2() and Pipe() macros? /* * Adam Bozanich * Pipeline example */ #include<stdio.h> #include<sys/types.h> #include<signal.h> #include<sys/wait.h> #include<errno.h> #define DIE(str) { fprintf(stderr,"%s\n",str); exit(errno); } #define STDIN_FILENO 0 #define READFD 0 #define STDOUT_FILENO 1 #define WRITEFD 1 #define Dup2(a,b) ( dup2(a,b) >= 0 ) ? : ( perror("dup2()"), exit(errno) ) #define Pipe(fd) ( pipe(fd) >= 0 ) ? : ( perror("pipe()"), exit(errno) ) int doProcs(int,char**); int main(int argc, char **argv) { char *args[] = { "/bin/ls" , "/usr/bin/wc" , "/usr/bin/wc" }; int count = 3; if(doProcs(count,args)<0) DIE("doProcs()") exit(0); } int doProcs(int proc_count,char** procs) { int fd[2]; int i; int ret; pid_t pid; for( i = 0 ; i < proc_count - 1 ; i++ ) { Pipe(fd); if(fork() > 0) /* parent */ { Dup2( fd[ READFD ] , STDIN_FILENO ); close(fd[ READFD ]); close(fd[ WRITEFD ]); } else /* child */ { Dup2( fd[ WRITEFD ] , STDOUT_FILENO ); close(fd[ WRITEFD ]); close(fd[ READFD ]); execlp(procs[i],procs[i],NULL); exit(errno); } } if((pid = fork()) == 0) { execlp(procs[proc_count - 1],procs[proc_count - 1],NULL); exit(errno); } else { while(wait(NULL)!=-1); if(errno != ECHILD) printf("did not return ECHILD\n"); } return(0); }




[ Post a follow-up to this message ]



    Re: help w/ pipes  
Frank Hickman


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:31 PM

Here's the man pages...

dup2(2)                                                             dup2(2)

NAME
dup2 - duplicate an open file descriptor to a specific slot

SYNOPSIS
#include <unistd.h>

int dup2(int fildes, int fildes2);

DESCRIPTION
fildes is a file descriptor obtained from a creat(), open(), dup(),
fcntl(), or pipe() system call.

fildes2 is a non-negative integer less than the maximum value allowed
for file descriptors.

dup2() causes fildes2 to refer to the same file as fildes.  If fildes2
refers to an already open file, the open file is closed first.

The file descriptor returned by dup2() has the following in common
with fildes:

+  Same open file (or pipe).

+  Same file pointer (that is, both file descriptors share one
file pointer.)

+  Same access mode (read, write or read/write).

+  Same file status flags (see fcntl(2), F_DUPFD).

The new file descriptor is set to remain open across exec() system
calls.  See fcntl(2).

This routine is found in the C library.  Programs using dup2() but not
using other routines from the Berkeley importability library (such as
the routines described in bsdproc(2)) should not give the -lBSD option
to ld(1).

RETURN VALUE
Upon successful completion, dup2() returns the new file descriptor as
a non-negative integer, fildes2.  Otherwise, it returns -1 and sets
errno to indicate the error.

ERRORS
dup2() fails if the following is true:

[EBADF]        fildes is not a valid open file descriptor or fildes2
is not in the range of legal file descriptors.

[EINTR]        An attempt to close fildes2 was interrupted by a
signal.  The file is still open.


pipe(2)                                                             pipe(2)

NAME
pipe - create an interprocess channel

SYNOPSIS
int pipe(int fildes[2]);

DESCRIPTION
pipe() creates an I/O mechanism called a pipe and returns two file
descriptors, fildes[0] and fildes[1].  fildes[0] is opened for reading
and fildes[1] is opened for writing.

A read-only file descriptor fildes[0] accesses the data written to
fildes[1] on a first-in-first-out (FIFO) basis.  For details of the
I/O behavior of pipes see read(2) and write(2).

By default, HP-UX pipes are not STREAMS-based.  It is possible to
generate the kernel so that all pipes created on a system are
STREAMS-based.  This can only be done for HP-UX releases 10.0 and
later.  STREAMS-based FIFOs (created by mknod or mkfifo) are not
supported on HP-UX.

To generate a kernel that supports STREAMS-based pipes:

+  STREAMS/UX must be installed.

+  The module pipemod and the driver pipedev must be included in the
/stand/system file.  (When STREAMS/UX is installed, pipemod and
pipedev are automatically added to the system file.)

+  The tunable parameter "streampipes" must be set to 1 in the
/stand/system file.  (This is not automatically done when
STREAMS/UX is installed.)

+  The kernel must be generated and the system rebooted.  Once this is
done, all pipes created by pipe() will be STREAMS-based.

For more information, see STREAMS/UX for the HP 9000 Reference Manual.

HTH
============
Frank Hickman
NobleSoft, Inc.
============
Replace the _nosp@m_ with @ to reply.

"Adam Bozanich" <abozan01@ccsf.edu> wrote in message
news:Pine.HPX.4.44.0312141858050.13830-100000@hills.ccsf.cc.ca.us...
quote:
> > > On Wed, 10 Dec 2003, inf wrote: > > > Thanks inf. I checked out strace, but I'm running FreeBSD and they > require linux emulation to run strace. I think it may be the same as a > native program 'ktrace', but I haven't had time to look into it. > > I finally got a chance to work on this project some more and got a working > pipeline example now. Thanks to all who replied. > > I am having a problem with my macros on my schools server (HPUX), maybe > someone can tell me the correct syntax for the Dup2() and Pipe() macros? > > /* > * Adam Bozanich > * Pipeline example > */ > #include<stdio.h> > #include<sys/types.h> > #include<signal.h> > #include<sys/wait.h> > #include<errno.h> > > #define DIE(str) { fprintf(stderr,"%s\n",str); exit(errno); } > > #define STDIN_FILENO 0 > #define READFD 0 > #define STDOUT_FILENO 1 > #define WRITEFD 1 > > #define Dup2(a,b) ( dup2(a,b) >= 0 ) ? : ( perror("dup2()"),
exit(errno))
quote:
> #define Pipe(fd) ( pipe(fd) >= 0 ) ? : ( perror("pipe()"),
exit(errno))
quote:
> > int doProcs(int,char**); > > int main(int argc, char **argv) > { > char *args[] = { "/bin/ls" , "/usr/bin/wc" , "/usr/bin/wc" }; > int count = 3; > > if(doProcs(count,args)<0) > DIE("doProcs()") > exit(0); > } > > int doProcs(int proc_count,char** procs) > { > int fd[2]; > int i; > int ret; > pid_t pid; > > for( i = 0 ; i < proc_count - 1 ; i++ ) > { > Pipe(fd); > > if(fork() > 0) /* parent */ > { > Dup2( fd[ READFD ] , STDIN_FILENO ); > > close(fd[ READFD ]); > close(fd[ WRITEFD ]); > } > else /* child */ > { > Dup2( fd[ WRITEFD ] , STDOUT_FILENO ); > > close(fd[ WRITEFD ]); > close(fd[ READFD ]); > > execlp(procs[i],procs[i],NULL); > > exit(errno); > } > } > > if((pid = fork()) == 0) > { > execlp(procs[proc_count - 1],procs[proc_count - 1],NULL); > exit(errno); > } > else > { > while(wait(NULL)!=-1); > if(errno != ECHILD) > printf("did not return ECHILD\n"); > } > > return(0); > } > > >




[ Post a follow-up to this message ]



    Re: help w/ pipes  
Adam Bozanich


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
01-23-04 10:31 PM



On Sun, 14 Dec 2003, Frank Hickman wrote:
quote:
> Here's the man pages... > > dup2(2) dup2( 2) > > NAME > dup2 - duplicate an open file descriptor to a specific slot > > SYNOPSIS > #include <unistd.h> > > int dup2(int fildes, int fildes2); >
<snip> I don't really understand your post. Are you suggesting that I am using pip e() incorrectly? If so, why not just say that? Or are you telling me that I sh ould have included unistd.h in my sample code? Sorry about that one, but I figur ed people would be able to throw that line in if they need. Is it really neces sary if all I am asking for is some help on basic macro syntax? Please elaborate if you have anything that would be of any use to say. -Adam [QUOTE] > > "Adam Bozanich" <abozan01@ccsf.edu> wrote in message > news:Pine.HPX.4.44.0312141858050.13830-100000@hills.ccsf.cc.ca.us...




[ Post a follow-up to this message ]



    Sponsored Links  




 





   All times are GMT. The time now is 01:22 PM.      Post New Thread    Post A Reply      
Pages (3): [1] 2 3 »   Last Thread   Next Thread Next


Most Popular forums 

Forum Jump:
Rate This Thread:

Forum Rules:
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is OFF
vB code is ON
Smilies are ON
[IMG] code is OFF
 
Medical and Health forum | Computer Games Reviews | Graphics design forum

Back To The Top
Home | Usercp | Faq | Register