tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Old curses puzzle
This is about a now-rather-old curses - the one that shipped with 5.2.
I don't know if anyone remembers enough to give me any useful pointers,
but figured it won't hurt to ask.
I've got a program. It uses curses(3) for its user interface. It
talks to, potentially, various hardware; as a result, it wants to run
everything non-blocking.
This has a tendency to lose output data, since curses does not expect
its output to be nonblocking.
So I use funopen to create a read stream that always returns 0 and a
write stream that writes to my nonblocking stdout mechanism, and use
newterm() with those streams.
The program takes command-line options which can specify what hardware
to talk to in various respects. If I start it with any of those
options, it all works fine. The display looks like (|s added)
| Control which mock?
|
| > Transceiver
| GPS
| Inclinometer
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
|
| Q quit, j/k down/up, RET select, C config
which is exactly what it should look like. But, if I start it with no
options, I instead get
| Control which mock?
|
| > Transceiver
| GPS
| Inclinometer
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
| ~
|
| Q quit, j/k down/up, RET select, C config
I've been unable to figure out what's wrong. Since the program talks
to serial lines, I thought perhaps something was misfiring in my serial
line code and it was corrupting the settings on stdout.
It's not that simple. stty -f <tty> everything, from another window,
produces identical output for the two cases. I ran it both ways under
ktrace, kdumped them, stripped the process IDs with sed, and diffed the
results. I can provide the full kdump outputs if that would help, but
the only differences are
(1) The syscalls resulting from the command-line args. (I told it to
use network interface fnord0, which does not exist; it opens /dev/bpf,
tries to set it up, and of course fails.)
(2) A few address changes because the the network interface setup
failure involves mmap()ping /usr/share/nls/nls.alias and
/usr/share/nls/C/libc.cat, leading to future mmap()s, in particular
malloc()ed memory, returning different addresses. At first I had lots
of address changes because the command-line args moved the stack by 24
bytes, so I added another command-line option of the same length which
takes an argument and ignores it; this made that difference go away.
(3) Exact data read from /dev/random (the program wants a little
randomness).
(4) curses output.
In particular, the curses output, as passed to write(), differs,
leading me to think that something is confusing curses:
- ..... 1 mocks CALL writev(1,0x7f7ffd401180,2)
+ ..... 1 mocks CALL writev(1,0x7f7ffd402180,2)
- ..... 1 mocks GIO fd 1 wrote 168 bytes
+ ..... 1 mocks GIO fd 1 wrote 187 bytes
" \^F0.0.\fControl which mock?\^P\n\n> Transceive\
- r\n GPS\n Inclinometer\n~\n~\n~\n~\n~\n~\n~\n~\n~\n~\n~\n~\n~\n~\n~\
+ r\r\n GPS\n\b\b\bInclinometer\r\n~\n\b~\n\b~\n\b~\n\b~\n\b~\n\b~\n\b~\
- \n~\n~\^RQ quit, j/k down/up, RET select, C config\^F23.79."
+ \n\b~\n\b~\n\b~\n\b~\n\b~\n\b~\n\b~\n\b~\n\b~\^RQ quit, j/k down/up, R\
+ ET select, C config\^F23.79."
- ..... 1 mocks RET writev 168/0xa8
+ ..... 1 mocks RET writev 187/0xbb
It looks to me as though curses thinks the tty is in ONLCR mode in the
`broken' case. Obviously something relevant differs, but I'm baffled
as to what.
Because curses.h and termios.h litter their callers with random
symbols, not well constrained into any particular part of the
namespace, I segregated all the curses code off into its own source
file, tui.c; none of the other source files even include curses.h.
(One other file includes termios.h, because one of the kinds of
hardware the program can talk to is serial ports. None of that code
should be getting called differently between the two runs.) I then
added tracing, to log every call into and return from tui.c.
That log is identical between failing and working runs; since all
curses calls are made from that file, the sequence of calls into curses
is also identical. I ran it under gdb and verified that my funopen()
write callback is indeed getting used in each case, and the data passed
to it agrees with the kdump output above in at least the first hundred
bytes or so (I didn't check the whoe buffer in detail).
Also, the kdump output indicates that all the tty ioctls done are
identical and set/get identical struct termios data blobs.
So, I'm wondering if anyone can think of any useful angle of attack
here, in particular any reason curses might have a different idea of
the `tty' output modes between the two runs, or anything else that
could produce this behaviour. I'm going to be lifting the hood of
curses to see if I can figure this out, but if anyone does have any
idea, it could save me a lot of thrashing about....
/~\ The ASCII Mouse
\ / Ribbon Campaign
X Against HTML mouse%rodents-montreal.org@localhost
/ \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
Home |
Main Index |
Thread Index |
Old Index