X-Spam-Check-By: sourceware.org Message-ID: <446C153A.9000105@cwilson.fastmail.fm> Date: Thu, 18 May 2006 02:33:30 -0400 From: Charles Wilson User-Agent: Thunderbird 1.5.0.2 (Windows/20060308) MIME-Version: 1.0 To: cygwin AT cygwin DOT com Subject: Re: rvxt-20050409-1 console problem [SUMMARY] References: <44695649 DOT 9080001 AT cwilson DOT fastmail DOT fm> In-Reply-To: <44695649.9080001@cwilson.fastmail.fm> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com 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/