rvxt-20050409-1 console problem [SUMMARY]

Charles Wilson cygwin@cwilson.fastmail.fm
Thu May 18 06:33:00 GMT 2006


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/



More information about the Cygwin mailing list