Hello,
I'm trying to implement synchronous interprocess communication where the
reader blocks until data is available and (the important thing) the
sender blocks until the sent data is fully read by the other side. I
thought this could be done using a pty/tty couple, but the sender
continues execution before the data has been read, so that it seems the
data is somewhere buffered. I know that such a communication will reduce
performance, but that doesn't matter in this case. The man page for
open(..) showed the a flag O_SYNC, which doesn't make any difference.
Another interesting flag is O_DIRECT, which doesn't seem to be defined.
cfmakeraw() didn't work either.
Below is my test program, where the output should be "a b c d", but in
fact it is "b d a c", which shows that the child continues before the
parent has read the data (because the parent is still sleeping while the
child performs it's output).
The solution will be required for an execlp()'ed child later, so I
cannot force the child to wait in any other way. Any solution using a
pipe or something similar would be welcome, too.
Thank you very much,
Alex J.
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pty.h>
#include <termios.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static char pty1[] = "pqr";
static char pty2[] = "0123456789abcdef";
int pty = -1;
int tty = -1;
/* open pty/tty couple */
/* child writes to tty */
/* parent reads from pty */
open_pty()
{
char ptyname[20];
char ttyname[20];
char *c1 = pty1;
while(*c1 && pty < 0 && tty < 0)
{
char *c2 = pty2;
while(*c2 && pty < 0 && tty < 0)
{
printf("trying: /dev/pty%c%c\n",*c1,*c2);
sprintf(ptyname,"/dev/pty%c%c",*c1,*c2);
if( (pty = open(ptyname, O_RDWR /*| O_SYNC*/) ) != -1 )
{
sprintf(ttyname,"/dev/tty%c%c",*c1,*c2);
if( (tty = open(ttyname, O_RDWR /*| O_SYNC*/) ) == -1 )
{
perror(ttyname);
close(pty);
pty = -1;
}
}
c2++;
}
c1++;
}
if(pty < 0)
{
perror("pty");
exit(1);
}
}
start_child(char *child)
{
open_pty();
switch(fork())
{
case 0:
{
/* child */
close(pty);
/* disable output buffering */
struct termios tios;
if(tcgetattr(tty, &tios) < 0)
{
perror("tcgetattr");
exit(1);
}
tios.c_cc[VMIN] = 0;
tios.c_lflag &= ~(ECHO|ICANON);
if(tcsetattr(tty, TCSANOW, &tios) < 0)
{
perror("tcsetattr");
exit(1);
}
sleep(1); // wait for parent applying its pty settings.
required?
/* TEST OUTPUT */
write(tty, ">a<", 3);
write(fileno(stderr), ">b<", 3);
write(tty, ">c<", 3);
write(fileno(stderr), ">d<", 3);
/* exec child program */
//execlp(child,child,NULL);
//perror("execlp");
exit(1);
break;
}
case -1:
{
perror("fork");
exit(1);
break;
}
default:
{
/* parent */
close(tty);
/* disable pty input buffering */
struct termios tios;
if(tcgetattr(pty, &tios) < 0)
{
perror("tcgetattr");
exit(1);
}
tios.c_cc[VMIN] = 0;
tios.c_lflag &= ~(ECHO|ICANON);
if(tcsetattr(pty, TCSANOW, &tios) < 0)
{
perror("tcsetattr");
return 0;
}
break;
}
} // end of switch
}
/* read from child */
char *read_child(char *buf, int len)
{
char c;
int i = 0;
while( (read(pty, &c, 1) == 1) && (i < len-1) )
{
if(c == '\n')
break;
else
buf[i++] = c;
}
buf[i] = 0;
return buf;
}
int main(int argc, char** argv)
{
char buf[1024];
start_child("sh");
sleep(3);
printf("read -> %s\n", read_child(buf, sizeof(buf) ) );
return 0;
}
output:
======
b d a c
|
|
0
|
|
|
|
Reply
|
Alex
|
8/6/2004 8:29:54 PM |
|
In article <cf0po5$91h$07$1@news.t-online.com>,
"Alex Jones" <dontlikespam@email.com> wrote:
> Hello,
>
> I'm trying to implement synchronous interprocess communication where the
> reader blocks until data is available and (the important thing) the
> sender blocks until the sent data is fully read by the other side. I
> thought this could be done using a pty/tty couple, but the sender
> continues execution before the data has been read, so that it seems the
> data is somewhere buffered. I know that such a communication will reduce
> performance, but that doesn't matter in this case. The man page for
> open(..) showed the a flag O_SYNC, which doesn't make any difference.
> Another interesting flag is O_DIRECT, which doesn't seem to be defined.
> cfmakeraw() didn't work either.
I don't think any of the standard IPC mechanisms provide this feature.
I suggest you use a semaphore to implement the blocking. After the
writer writes his data, he waits on the semaphore, which the reader
signals after he has completed reading the data.
--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
|
|
0
|
|
|
|
Reply
|
Barry
|
8/7/2004 4:43:49 AM
|
|
"Barry Margolin" <barmar@alum.mit.edu> wrote in message
news:barmar-631F5F.00434907082004@comcast.dca.giganews.com...
> In article <cf0po5$91h$07$1@news.t-online.com>,
> "Alex Jones" <dontlikespam@email.com> wrote:
>
> > Hello,
> >
> > I'm trying to implement synchronous interprocess communication where
the
> > reader blocks until data is available and (the important thing) the
> > sender blocks until the sent data is fully read by the other side. I
> > thought this could be done using a pty/tty couple, but the sender
> > continues execution before the data has been read, so that it seems
the
> > data is somewhere buffered. I know that such a communication will
reduce
> > performance, but that doesn't matter in this case. The man page for
> > open(..) showed the a flag O_SYNC, which doesn't make any
difference.
> > Another interesting flag is O_DIRECT, which doesn't seem to be
defined.
> > cfmakeraw() didn't work either.
>
> I don't think any of the standard IPC mechanisms provide this feature.
> I suggest you use a semaphore to implement the blocking. After the
> writer writes his data, he waits on the semaphore, which the reader
> signals after he has completed reading the data.
>
> --
> Barry Margolin, barmar@alum.mit.edu
> Arlington, MA
> *** PLEASE post questions in newsgroups, not directly to me ***
Thanks for your response, but that won't be possible, because the child
process (the writer) will be a compiled program (using execlp() ) later,
not written by me. But is it really _impossible_ to just create a
completely unbuffered stream for communication??
Alex J.
|
|
0
|
|
|
|
Reply
|
Alex
|
8/7/2004 12:51:48 PM
|
|
Alex Jones <dontlikespam@email.com> wrote:
> "Barry Margolin" <barmar@alum.mit.edu> wrote in message
> news:barmar-631F5F.00434907082004@comcast.dca.giganews.com...
>> In article <cf0po5$91h$07$1@news.t-online.com>,
>> "Alex Jones" <dontlikespam@email.com> wrote:
>> > I'm trying to implement synchronous interprocess communication where
> the
>> > reader blocks until data is available and (the important thing) the
>> > sender blocks until the sent data is fully read by the other side. I
>> > thought this could be done using a pty/tty couple, but the sender
>> > continues execution before the data has been read, so that it seems
> the
>> > data is somewhere buffered. I know that such a communication will
> reduce
>> > performance, but that doesn't matter in this case. The man page for
>> > open(..) showed the a flag O_SYNC, which doesn't make any
> difference.
>> > Another interesting flag is O_DIRECT, which doesn't seem to be
> defined.
>> > cfmakeraw() didn't work either.
>>
>> I don't think any of the standard IPC mechanisms provide this feature.
>> I suggest you use a semaphore to implement the blocking. After the
>> writer writes his data, he waits on the semaphore, which the reader
>> signals after he has completed reading the data.
> Thanks for your response, but that won't be possible, because the child
> process (the writer) will be a compiled program (using execlp() ) later,
> not written by me. But is it really _impossible_ to just create a
> completely unbuffered stream for communication??
When you have no control about the writer how should you be able to
control if it writes without buffering? If the writer uses e.g. the
C standard I/O function and doesn't set them explicitely to unbuf-
fered mode there's hardly anything you can do about that (short of
fiddling with the libc it's using) - the data will stay in the
writers side I/O buffer (controlled by the I/O functions) which will
only get flushed when it's full (if the writer thinks it's writing
to a file) or if there's a '\n' is in the stream (if the writer
assumes to be writing to a terminal). What you can achieve with
a set of pty's in between the processes is making the writer believe
it's talking to a terminal, thus flushing it's buffers on '\n', but
not more.
What kind of a program are you trying to write where on the one hand
you want absolute control about details like buffering down to a
single byte level but on the other hand you have no influence about
the behavior of the sides? If you would give a bit more of a complete
picture perhaps there are alternatives you didn't take into account
yet.
Regards, Jens
--
\ Jens Thoms Toerring ___ Jens.Toerring@physik.fu-berlin.de
\__________________________ http://www.toerring.de
|
|
0
|
|
|
|
Reply
|
Jens
|
8/7/2004 2:13:16 PM
|
|
On 2004-08-07, Alex Jones <dontlikespam@email.com> wrote:
>
> But is it really _impossible_ to just create a completely unbuffered
> stream for communication??
>
Come to thing of it, what you are asking for is a way to post a
quantum of data to a process (a "datum"), and get notified when this
datum has been acted-upon by the other process. In unix, no there is
no *standard* way to do this, especially if this involves processes
you have no control upon (i.e. their code is not written by you). If,
on the other hand you write both ends then there are obviously several
ways to acieve this behavior, but not with a single system or library
call.
/npat
|
|
0
|
|
|
|
Reply
|
Nick
|
8/7/2004 11:57:57 PM
|
|
On Sat, 07 Aug 2004 14:51:48 +0200, Alex Jones wrote:
> Thanks for your response, but that won't be possible, because the child
> process (the writer) will be a compiled program (using execlp() ) later,
> not written by me. But is it really _impossible_ to just create a
> completely unbuffered stream for communication??
There is no standard method for doing so. I'm not even aware of a
non-standard method. All the standard UNIX communication mechanisms
(pipes, sockets, ptys, etc.) provide some buffering. Even a tty/pty in
"raw" mode will buffer the data. And even if those mechanisms provided no
buffering you wouldn't necessarily be able to achieve your goal. Since the
data producer may be using user level buffering (such as that provided by
the stdio library routines) there is no guarantee that a "write" operation
will even result in the data being immediately handed to the operating
system.
|
|
0
|
|
|
|
Reply
|
Kurtis
|
8/8/2004 1:00:37 AM
|
|
|
5 Replies
261 Views
(page loaded in 0.313 seconds)
|