tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: flock(2): locking against itself?



On Sun, Apr 16, 2023 at 12:28:03AM -0400, Mouse wrote:
 > Back on 2023-03-30, I posted to tech-kern on a thread that had drifted
 > off-topic for tech-kern, into tech-userlevel territory.  I was writing
 > about bad interactions between libcurses and nonblocking I/O.
 > 
 > [...]
 >
 > It seems to me that there are multiple issues with libcurses here.
 > 
 > (1) It does not get along with input and/or output being set
 > non-blocking.

Bug.

While, in principle, when you're using curses it owns both the input
and the output, in practice because curses input can't cope with
select loops it's common for curses applications to use curses only
for output and do other things with the input, so it's reasonable for
the input to be nonblocking and this can make the output nonblocking
as well.

However, I'd expect that getting a second open of the same tty for the
output would work around this. (dup isn't enough, but a new open
should work, because non-blocking I/O is a file-handle-level mode, not
a tty driver mode.)

Since it apparently doesn't my guess is that there are places in the
curses code that don't clearly distinguish input and output and this
causes it to get tangled in its shoelaces when they aren't the same
object.

Meanwhile, curses not being able to interact with select loops is also
a bug (one I've complained about before) and, realistically, one
that'll need fixing for successful use of nonblocking input _with_
curses.

Unfortunately fixing all of this is not trivial, so nobody's likely to
take it up anytime soon.

 > (2) newterm() takes FILE *s rather than file descriptors, but requires
 > for correct operation that they be connected to file descriptors anyway
 > (it uses fileno() all over the place).
 >
 > (3) Even if the FILE *s _are_ connected to file descriptors, it does
 > not work correctly unless those descriptors are connected directly to
 > tty devices.

My recommendation for this would be to restructure the whole thing to
use its own handle structure internally that has an ops table so at
least the mess is contained in one place. But this is a large
undertaking too.

Then of course you also need a nonstandard replacement newterm() that
provides the extra ops needed.

 > (4) There's no way, without going under stdio's hood, to create a stdio
 > stream that operates like a funopen()ed stream but allows the caller to
 > arrange for fileno() to return something useful.

That probably isn't the right direction to go in, I think.

 > At this point, I'm tempted to pull the screen-updating smarts out of
 > libcurses (that's the only part I want to use, here) and make it
 > available under an API that has absolutely nothing OS-dependent about
 > it, possibly excepting terminal type capabilitiy lookup.  So, I'm
 > writing to ask:
 > 
 > (a) Does anyone have any other ideas, not mentioned above, for how to
 > address these issues?

None that aren't super expensive.

 > (b) Does anyone know of any work done towards pulling the screen
 > updater out of curses, so it can be used without all the baggage tied
 > to the OS that libcurses imposes?
 > 
 > (c) If not, would there be any interest in such a thing?

As you probably remember I've argued at length in the past that
memory-mapped screens should have a memory-mapped screen interface at
the device level. (In which case that screen updater is only needed as
a driver for serial-attached terminals.) However, that's also a huge
undertaking and I've never actually done the work.

Anyway, my guess is that pulling the screen updater out is roughly the
same as what I suggested above about using its own handle structure
internally, if you want something that works more or less like the
current curses (you feed it text, it outputs other text).

It might also to be possible to split it at a level where the ops are
basically "write a chunk of text at this location" and calls for the
various termcap capabilities it knows about, and then you plug it into
termcap explicitly, but that seems like even more work. Although it
also provides a framework that one could use to output to a graphics
system window, which would be a nice thing to have.

If opening a second fd for output doesn't work and debugging what's
happening with that isn't feasible, I don't think there's any approach
here that isn't a large pain.

I guess the other question is: for what you're doing, do you really
need the full screen updater? Unless it's intended to talk over a slow
serial line (like, less than 19200 bps) a much simpler line-at-a-time
updater will serve perfectly well. I imagine there are some extant
implementations already, and if not, writing one will probably be less
work than grinding the curses we have.

-- 
David A. Holland
dholland%netbsd.org@localhost


Home | Main Index | Thread Index | Old Index