 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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 ]
|
|
|
 |
|
 |
|
 |
|
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. |
 |
|
|
 |
|
 |
|
|
 |
|
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
|
 |
|
 |
|