|
From: Hans-Bernhard B. <br...@ph...> - 2004-01-10 14:40:55
|
On Sat, 10 Jan 2004, Daniel J Sebald wrote:
[....]
> You'll have to forgive me. I've tried following the code to see exactly
> the path that the commands come in via stdin, where the pipe is read for
> the mouse, etc. and I'm having a difficult time keeping track of it all.
The core function is generally term->waitforinput(), which in the case of
the x11 terminal is provided by X11_waitforinput() in term/x11.trm.
There are different call paths leading there. Let me provide an overview.
Cscope helps:
C symbol: waitforinput
File Function Line
0 term_api.h <global> 172 int (*waitforinput) __PROTO((void ));
1 command.c pause_command 961 if (term && term->waitforinput) {
2 command.c pause_command 964 term->waitforinput();
3 command.c fgets_ipc 2212 if (term && term->waitforinput) {
4 command.c fgets_ipc 2219 c = term->waitforinput();
5 readline.c getc_wrapper 84 if (term && term->waitforinput && interactive) {
6 readline.c getc_wrapper 88 c = term->waitforinput();
7 readline.c ansi_getc 775 if (term && term->waitforinput && interactive)
8 readline.c ansi_getc 776 c = term->waitforinput();
The call paths ultimately start at read_line in command.c. I'll assume
MOUSE is active:
no READLINE (neither gnuplot's own, nor -lreadline):
GET_STRING ==> fgets
some READLINE, !interactive:
fgets_ipc ==> term->waitforinput
GNU libreadline, interactive:
read_line ==> rlgets ==> readline_ipc ==> rl_callback_read_char
(getc_wrapper passed to libreadline as input hook)
gnuplot readline.c, interactive:
read_line ==> rlgets ==> readline_ipc ==> readline
==> special_getc ==> ansi_getc
So that's how we get to the core function. Now let's look at
X11_waitforinput itself: it uses select() to dispatch between the two
input streams. The root of all our trouble is that select() operates not
on <stdio.h> objects like stdin, but rather on unbuffered Unix file
handles. I.e. select doesn't know a thing about <stdio.h> buffering.
> I find it hard to fathom that this is not possible.
It's quite certainly possible. The tricky part is to make it possible
in the context of a massively portable program like gnuplot, without
breaking the whole program for use on other platforms.
> I mean, doesn't this seem like a fundamental task of operating systems?
> That is, to distribute I/O around the system? Let's consider an fread()
> or a fgets() or fgetc().
For starters, fgetc() and friends aren't even functions of the operating
system to begin with. They're functions of the C runtime library --- but
ISO/ANSI C doesn't standardize asynchronous I/O.
> Can't I just do an fread() from the stdin (the place where the commands
> are typed in) and whatever is there I store in a "command buffer" and as
> I'm putting the characters in a command buffer I watch for the "new
> line" or "end of gnuplot command" character.
No, you can't. The reason is that file I/O on Unix (and all other
platforms I've seen) is by default a "blocking" operation:
> If there is nothing in the buffer or there are less characters than
> asked for, doesn't the fread() simple return and EOF or -1 or number of
> bytes read?
If there's buffered input, but less than requested, it'll return what
there is. But if there's currently _nothing_ in the buffer, it won't
return at all until there is. You only get an EOF condition if the stream
is actually ended (typical Unix setup: if you typed Ctrl-D at the
keyboard), not if there's just no buffered input available at the moment.
> >F) The usual way around this dilemma is to use poll or select to notify
> > us when either or both of two input streams is presenting new data.
> > We currently use select in X11_waitforinput().
> >
>
> Yes, this is one way. But if "fread()" is inherently forced to return
> something even if the buffer is empty, isn't that a form of polling the
> input as well?
The problem is we *can't* force fread() to do that. Non-blocking I/O
is not foreseen in the context of <stdio.h> functions.
> As I said before, it seems to me that current Gnuplot
> really isn't wanting polling for "characters available", rather it is
> attempting to poll for "gnuplot command in buffer available" and "mouse
> command in buffer available".
I'm quite sure that reading characters versus lines is unrelated to the
problem at hand.
> >G) Unfortunately, poll/select notification depends on whether the
> > input stream is buffered or non-buffered. I do not know if this is
> > supposed to be the case, but that's what we see in practice.
Indeed select() doesn't know a thing about buffering, so it will not
report a stream as having data available if all of it is buffered.
--
Hans-Bernhard Broeker (br...@ph...)
Even if all the snow were burnt, ashes would remain.
|