This is the mail archive of the
cygwin
mailing list for the Cygwin project.
Re: rvxt-20050409-1 console problem [SUMMARY]
Charles Wilson wrote:
(2) add the "smart" hide console code to rxvt-unicode-X and remove the
brute-force hide console code. Otherwise, the Igors of the world will
have the same "where'd my console go" problem with rxvt-unicode-X.
There is a downside to this. As Brian mentioned "run" is not going away
-- because without it (e.g. if rxvt[-unicode-X] hides its own console
after-the-fact) you will always get the briefly flashing cmd console.
Not a big deal, but annoying. But, rxvt-unicode-X can't be used with
run if --login (100% CPU suckage). I dug into this, and discovered a
few things:
rxvt-unicode-X has a main event loop that is completely rewritten from
the one in rxvt. So it's not surprising that it behaves somewhat
differently. What's going on in the problematic case (100% CPU usage if
run+urxvt-X+loginShell=true) is that a select() call is always returning
immediately with "data waiting" -- except that there's not REALLY any
data waiting.
Because run.exe lauches the child process with no console -- not even a
hidden one, actually -- the stdin/stdout/stderr handles are not
initialized. [1] Somewhere -- and I haven't figured out where, yet,
because the obvious place is NOT it -- rxvt-unicode-X is reopening stdin
to /dev/null (well, technically, it's opening file descriptor 0 to the
file /dev/null...it might not be "thinking" of it in terms of "stdin",
per se. dup2() will automatically use the lowest available file
descriptor -- and if 0 [stdin] is available, suddenly you've got stdin
open again.)
Anyway, /dev/null is of course always "ready" but never actually has any
data. So the event loop never 'hangs out' in the select. Instead, it's
acting like a polling spinlock -- and that's bad.
So, I get the following repeated over and over -- sucking 100% CPU (and
note the second line!).
===================
31 447 [main] rxvt 2744 cygwin_select: 7, 0x22EDC0, 0x22EDB8,
0x0, 0x0
52 499 [main] rxvt 2744 dtable::select_read: /dev/null fd 0
49 548 [main] rxvt 2744 dtable::select_read: fd 4
45 593 [main] rxvt 2744 dtable::select_read: /dev/ptmx fd 6
27 620 [main] rxvt 2744 cygwin_select: to NULL, ms FFFFFFFF
92 712 [main] rxvt 2744 cygwin_select: sel.always_ready 1
24 736 [main] rxvt 2744 select_stuff::cleanup: calling cleanup
routines
20 756 [main] rxvt 2744 socket_cleanup: si 0x0 si->thread 0x0
18 774 [main] rxvt 2744 socket_cleanup: returning
36 810 [main] rxvt 2744 peek_socket: considering handle 0x6D4
23 833 [main] rxvt 2744 peek_socket: adding read fd_set , fd 4
34 867 [main] rxvt 2744 peek_socket: WINSOCK_SELECT returned 0
20 887 [main] rxvt 2744 set_bits: me 0x702AC0, testing fd 0
(/dev/null)
19 906 [main] rxvt 2744 set_bits: ready 1
18 924 [main] rxvt 2744 select_stuff::poll: returning 1
18 942 [main] rxvt 2744 select_stuff::cleanup: calling cleanup
routines
19 961 [main] rxvt 2744 select_stuff::~select_stuff: deleting
select records
67 1028 [main] rxvt 2744 set_signal_mask: oldmask 0x0, newmask
0x84002, mask_bits 0x0
19 1047 [main] rxvt 2744 set_signal_mask: not calling
sig_dispatch_pending
21 1068 [main] rxvt 2744 readv: readv (0, 0x22ED50, 1) blocking,
sigcatchers 3
21 1089 [main] rxvt 2744 readv: no need to call ready_for_read
20 1109 [main] rxvt 2744 fhandler_base::read: returning 0, binary
mode
18 1127 [main] rxvt 2744 readv: 0 = readv (0, 0x22ED50, 1), errno 0
21 1148 [main] rxvt 2744 set_signal_mask: oldmask 0x84002,
newmask 0x0, mask_bits 0x84002
20 1168 [main] rxvt 2744 cygwin_select: 7, 0x22EDC0, 0x22EDB8,
0x0, 0x0
===================
[1] Here's the important bit from run.exe:
memset (&start, 0, sizeof (start));
start.cb = sizeof (start);
start.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
start.wShowWindow = SW_HIDE;
start.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
start.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
start.hStdError = GetStdHandle(STD_ERROR_HANDLE);
sec_attrs.nLength = sizeof (sec_attrs);
sec_attrs.lpSecurityDescriptor = NULL;
sec_attrs.bInheritHandle = FALSE;
if (CreateProcess (NULL, cmdline, &sec_attrs, NULL, TRUE, 0,
NULL, NULL, &start, &child))
{
Sure, it's *supposedly* setting start.hStdInput and friends to The Right
Thing, but according to MSDN (in the AllocConsole() description):
"GUI applications are initialized without a console. Console
applications are initialized with a console, unless they are created as
detached processes (by calling the CreateProcess function with the
DETACHED_PROCESS flag)."
Since run.exe is a GUI app, it has no console at all -- and therefore
GetStdHandle() returns INVALID_HANDLE_VALUE, which isn't a very nice
thing to initialize start.hStdInput and friends to.
But here's the thing: run.exe's job is to launch an application without
a *visible* console. **NOT** necessarily to launch the application with
no console whatsoever, and with closed stdio handles. It's "run.exe",
not "daemonize.exe" -- and some applications, even GUI apps, don't react
well when treated like daemons.
But run.exe can't simply call AllocConsole() -- there's no [easy] way to
say "AllocConsole(but make it hidden)". You'd have to AllocConsole and
then use the hide_console routines -- and now you're back to flashing
windows again.
===================
What to do?
First, I believe there are two problems:
(1) rxvt-unicode-X really should handle having stdin closed (or set to
/dev/null) more gracefully. Why is stdin even being listened to in
the event loop, anyway? Or is this a dup2() problem, where the closed
fd 0 is being reused? Dunno. Needs more looking at.
(2) run.exe should try at least as hard as cygwin1.dll to provide for
the expectations of its clients: if possible, give them a hidden console
with working stdio. Again, it's "run.exe", not "daemonize.exe".
Well, I've got a patch for run.exe that borrows code from cygwin's
fhandler_init routines, to enable run.exe, a GUI app, to AllocConsole()
but NOT flash. To do this, it uses some routines in user32.dll that are
only available on WinNT/2k/XP -- so I did the whole
LoadLibrary/GetProcAddress dance with function pointers; end result
should be no change from current behavior for w95/98/Me. It would be
nice if there was some other code that could be used to similar purpose
on those older OSes -- maybe I need to 'borrow' from some other area of
cygwin...unfortunately, I have no w95/98/Me machine to test on, so I'm
hesistant to code blindly.
Anyway, with this change on WinXP(and presumably 2k/NT), rxvt-unicode-X
+ new-run.exe + loginShell = true works just fine, no 100% CPU suckage.
I'll post that patch in a new thread.
The second problem -- rxvt-unicode-X ought to behave better when it has
no stdin -- is a little more difficult. I need to verify that it
behaves just as badly on linux when launched via a daemonizer. If so,
then it's time for heavy duty debugging -- and maybe a report back to
the upstream developers. If not...err, uhm, well...I've been wrong
before...
(3) (b) forget about scripts. Use a special version of "run"
specifically for the purpose of switching between rxvt versions. For
user customizability, maybe it could read configuration info
from a file in /etc. This rxvt-launcher would be a -mwindows app, just
like run. It would use the checkX program (or borrow the code; sigh.
Time for a library?) to determine Xness, and launch the apropriate
client using !SW_VISIBLE, just like run. But it wouldn't have any of
run's introspection code ("what was my own argv[0]? Did it match
'run?????.exe' where ????? non-empty? Search PATH for ?????.) nor would
it need to have any PATH walking code at all -- require that
configuration info contain full PATH. (It would need to resolve
symlinks, tho).
I'm leaning toward this solution, in a more generic sense, like:
"gui-switcher.exe --config=/etc/rxvt-selector.conf"
It'll go into the checkX package since it'll leverage a lot of the same
code. And that's why I need to track down these issues with
rxvt-unicode-X+run+loginShell...'cause if they are not solved with
run.exe, they'll show up again with gui-switcher.exe.
--
Chuck
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Problem reports: http://cygwin.com/problems.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/