LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 05-11-2016, 04:47 PM   #1
KarenWest
Member
 
Registered: Jun 2011
Location: North Easton,MA
Distribution: currently Ubuntu Linux on my netbook while job searching, but also use Cygwin GNU tools on MSXP nb
Posts: 33

Rep: Reputation: Disabled
Smile ioctl FIONREAD and parent reading from a pipe child wrote to, sending to outfile


In the code below, src is an output pipe written to by a child process that the parent process is reading, and dst is an output file. Before this code is executed, the child process finished executing, and the SIGCHLD signal was received. Shouldn't the data written to the output pipe still be there when this code executed by the parents goes to read it? ioctl FIONREAD says zero bytes are available for reading from this pipe. Then there is an OS system error printed (Interrupted System Call ??). This is the output.

ioctl said 0 bytes are available to read from pipe
no data yet Interrupted system call
0 bytes were read from pipe and sent to output file

Also, are you allowed to redirect the first child process's standard output to a pipe, so that the next child process can redirect it's standard input to be from this pipe and then redirect this next child process's standard output to be to another pipe, that the parent can then read and send to the output file, once this next child is done running?

The reason I ask, is because when I run just one child process and redirect it's standard output to a pipe that the parent can read, it works fine, but when I do that with the second child process, there seems to be an error as described above.
Code:
    int n;
    int size = 0;
    if (ioctl (src, FIONREAD, &size) == -1) {
        perror ("ioctl");
        return -1;
    }
    printf("ioctl said %d bytes are available to read from pipe\n", size);
  
    if ( (n = read(src, line, MAXBUF)) < 0)
      printf("read error from pipe");
    else if (n == 0)
      {
	printf("no data yet %s \n",strerror(errno));
      }
    else
      {
	printf("parent read %d bytes read from child to send to output file\n", n);
      }

    line[n] = 0;  //null terminate
  
    if (fputs(line, dst) == EOF)
      printf("fputs error to output file\n");
    else
      {
	printf("parent wrote output to output file, read back from child exec\n");
	printf("print output data to file = %s\n", line);
      }

    printf("%d bytes were read from pipe and sent to output file\n",n);
    return n;
 
Old 05-11-2016, 08:48 PM   #2
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
I assume this is a FIFO (named pipe)?

A pipe is not designed for multiple children to write to - data can get damaged/out of order. When the child exits, the pipe gets an EOF, which terminates I/O until the FIFO is re-opened.

If you are using FIONREAD, the assumption is that that the I/O has been specified to be non-blocking. If it is blocking, then the read will block until the data is available or EOF occurs - in which case the FIONREAD is useless.

Using the FIONREAD allows you to do non-blocking I/O by reading the given "size" bytes - and no waiting is necessary. If you do try to read more than is there with nonblocking I/O, you get a "short read" result, and the read system call will return the number
of bytes actually read (which may be larger than the "size" retrieved by the FIONREAD as more data may have arrived after
the FIONREAD was performed, but before the read system call).

Very likely, you are using blocking I/O, and the read has blocked - when the child exits you get a signal (SIGCHLD) which will interrupt a blocking read.

If you want multiple children to write to this, perhaps you should be using a domain socket. It works similar to a pipe when used, but has the advantage of being able to be used like a socket with multiple clients. It can also be bidirectional, and you avoid the possibility of data corruption.

Last edited by jpollard; 05-11-2016 at 08:52 PM.
 
Old 05-12-2016, 03:56 PM   #3
KarenWest
Member
 
Registered: Jun 2011
Location: North Easton,MA
Distribution: currently Ubuntu Linux on my netbook while job searching, but also use Cygwin GNU tools on MSXP nb
Posts: 33

Original Poster
Rep: Reputation: Disabled
Actually, I am using 2 pipes. The first pipe is used to redirect the standard output from the first command to pipe1[1].
The second command then redirects its standard input to pipe1[0], so the output from the first command becomes the input
to the second command (command1 | command2).

However, I also have a pipe2 so that after command2 runs, the second child run from the parent, can have it's output go
to an output file. So the second command redirects its standard output to pipe2[1]. The parent can then monitor data
on pipe2[0] that it created, and take that data and output it to an output file.

However, it's having trouble getting the data from pipe2[1].

If I do not include the output file, my code works, as long as I send the data to standard out rather than the pipe2 for
the parent to read.

So I don't think it's a case that I need a socket? I've used sockets when I've dealt with server and client code. This
exercise was all about redirecting IO using pipes.

I'll have to look into whether I'm doing a blocking IO. Maybe that's the problem?
 
Old 05-12-2016, 04:09 PM   #4
KarenWest
Member
 
Registered: Jun 2011
Location: North Easton,MA
Distribution: currently Ubuntu Linux on my netbook while job searching, but also use Cygwin GNU tools on MSXP nb
Posts: 33

Original Poster
Rep: Reputation: Disabled
So what I should have done when I had the parent process create the pipes, is initialize cshell_pipe2 with:
Code:
int pipe2(int cshell_pipe2[2], int flags);
with this flag sent to the flags argument:

O_NONBLOCK
Set the O_NONBLOCK file status flag on the two new open file descriptions. Using this flag saves extra
calls to fcntl(2) to achieve the same result.

I will try that. I just did it by:

Code:
if ((pipe(cshell_pipe2) < 0))
	printf("pipe creation error");
Perhaps it's automatically a blocking pipe if you don't send it the flag O_NONBLOCK, as you mentioned.
I may not have time to try this until next week, but it was nice to have something new to try since I was stuck.
Thanks.
 
Old 05-12-2016, 05:23 PM   #5
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
Quote:
Originally Posted by KarenWest View Post
Actually, I am using 2 pipes. The first pipe is used to redirect the standard output from the first command to pipe1[1].
The second command then redirects its standard input to pipe1[0], so the output from the first command becomes the input
to the second command (command1 | command2).

However, I also have a pipe2 so that after command2 runs, the second child run from the parent, can have it's output go
to an output file. So the second command redirects its standard output to pipe2[1]. The parent can then monitor data
on pipe2[0] that it created, and take that data and output it to an output file.

However, it's having trouble getting the data from pipe2[1].

If I do not include the output file, my code works, as long as I send the data to standard out rather than the pipe2 for
the parent to read.

So I don't think it's a case that I need a socket? I've used sockets when I've dealt with server and client code. This
exercise was all about redirecting IO using pipes.

I'll have to look into whether I'm doing a blocking IO. Maybe that's the problem?
With two pipes, you get the problem of deadlock - both sides waiting to write (or read)...

That is why a socket works better. It is designed for bidirectional traffic, and can be synchronized - which two pipes cannot be (which is why they can deadlock).

Been there done that. One of my first communications activity used two pipes instead of a socket... didn't work very well, and frequently locked up.

Use a domain socket instead. You will get all the mechanics for handling I/O without the problems.

Last edited by jpollard; 05-12-2016 at 05:25 PM.
 
  


Reply

Tags
ioctl, pipe, redirect



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Sending Signal from Child Process to Parent Process : Not getting desired output thelink123 Linux - General 4 10-26-2012 09:05 PM
[SOLVED] Problems with FIFO pipe using a child and parent process mashhype Programming 5 11-22-2010 02:43 AM
ipc between parent and child processes using pipe rainman1985_2010 Programming 3 10-15-2010 03:30 AM
select() call does not detect data in pipe between parent and child program rasbambober Programming 5 09-24-2009 11:32 PM
File descriptors shared between child and parent causing parent to hang. bharadiaam Linux - Newbie 1 03-02-2009 01:01 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 11:15 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration