Linux - SoftwareThis forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Hmm, I like that much more than a system call to stty.
Except that it doesn't appear to work correctly. I suspect it is just consulting curses.COLS and curses.LINES variables which don't get updated automatically on resize event. Sticking with the stty call until I find something in the curses library that actually works.
SVN revision 456: Possible fix to resize the terminal window
As described in great detail above, the short story is that I use a system call to stty to determine the new values for lines and columns and then do the proper resizing of all three windows (main screen, statuswin, and titlewin) and the re-positioning of the status window.
Two caveats:
1. If current view is scoreboard or listings, a resize event moves the cursor back to the top of the records.
2. The code may still crash if the window is made smaller than 24x80.
Except that it doesn't appear to work correctly. I suspect it is just consulting curses.COLS and curses.LINES variables which don't get updated automatically on resize event. Sticking with the stty call until I find something in the curses library that actually works.
I doubt it consults curses.COLS and curses.LINES - tigetnum() is a terminfo call. Using tigetnum() seems to give off-by-one errors quite regularly if substituted for the stty calls in your code (that's what I notice anyway). It is this kind of thing that makes curses so frustrating. Anyway, your approach seems to be the way to go.
However there is still something odd going on even with the stty system calls, because if you do a lot of resizing of the window in a short period of time the select loop gets into an inconsistent state. This may be connected with the fact that SIGWINCH interrupts are causing some of the curses calls in the else block in the select exception handling code to return with an EINTR error. This can be demonstrated by putting a call to time.sleep(5) at the beginning of the else block: presumably what is happening is that the call to time.sleep() unblocks when a SIGWINCH interrupt arrives, although I am not sure why this does not itself result in an unhandled exception. As it happens including that sleep also helps mask the inconsistent state of the select loop.
OK. The attached patch is the best I can think of doing with this. It keeps the curses updates coming through at a rate that can be handled. It means that there can be up to a one second delay before the final sizing takes place but the effect is not horribly displeasing. As I suspected, it is necessary to block SIGWINCH while the wait is taking place. You might want to experiment with a smaller timeout.
It does not appear to be necessary to update curses.LINES and curses.COLS by hand as the call to resizeterm() seems to do that for you, but it appears harmless.
Hmm, the patch was missing. Lets try again with a 'txt' ending.
I cannot reproduce the problem this is trying to fix, namely too many resizes in a short period causes a crash. Maybe my system is slow enough or maybe I'm just slow enough in resizing my windows. However, I think it looks kinda wonky to take a second to resize. User perception would be, "why does it take that long?" Can you try a time.sleep(0.5) and see if that also masks the problem you see?
I also wonder if we are trying to over-engineer this to be correct when good enough might be all it needs. When you perform resizing in your normal use case (e.g. not actively looking for a failure), do you still see crashes?
Interesting. On testing this further I see it is related to the speed of the machine. I have tested on a netbook and the effect is just about noticeable but limited and certainly not troublesome. On my dual core 3.3GHz sandybridge desktop it is very noticeable. I can reproduce it by taking the bottom right corner of the terminal window with the mouse, then waggling the bottom right corner around meaningfully with the mouse for about 3 or 4 seconds and then pressing an actionable key such as L or Q. The program does not usually crash (in the sense of end), although occasionally it does, but normally the event loop just goes wild and the only thing you can do is terminate the program with Ctrl-C or similar (Q ceases to work). It is difficult to describe - you have to see it really.
I have reduced the 1 second delay to 0.3 seconds and it is still effective in throttling the rate of interrupt events to avoid this. At 0.1 seconds I can just notice some artifacts, although they are not troublesome, and at 0.01 seconds it is as bad as not having a delay at all.
My desktop is fast but not super fast. It might be useful for someone with an 8 core machine to give it a try. Band aids for timing issues of this kind are a little worrying: my desktop is a little over 5 times faster than my netbook at doing things such as compiling kernels, but even so it is difficult to see why there should be this difference. I do not know a great deal of python (I am much more comfortable with C++, scheme or javascript) but I find python's wrapping of select puzzling as a whole. It is with the select wrapper where the problem may lie.
Interesting. On testing this further I see it is related to the speed of the machine. I have tested on a netbook and the effect is just about noticeable but limited and certainly not troublesome. On my dual core 3.3GHz sandybridge desktop it is very noticeable. I can reproduce it by taking the bottom right corner of the terminal window with the mouse, then waggling the bottom right corner around meaningfully with the mouse for about 3 or 4 seconds and then pressing an actionable key such as L or Q. The program does not usually crash (in the sense of end), although occasionally it does, but normally the event loop just goes wild and the only thing you can do is terminate the program with Ctrl-C or similar (Q ceases to work). It is difficult to describe - you have to see it really.
I have reduced the 1 second delay to 0.3 seconds and it is still effective in throttling the rate of interrupt events to avoid this. At 0.1 seconds I can just notice some artifacts, although they are not troublesome, and at 0.01 seconds it is as bad as not having a delay at all.
My desktop is fast but not super fast. It might be useful for someone with an 8 core machine to give it a try. Band aids for timing issues of this kind are a little worrying: my desktop is a little over 5 times faster than my netbook at doing things such as compiling kernels, but even so it is difficult to see why there should be this difference. I do not know a great deal of python (I am much more comfortable with C++, scheme or javascript) but I find python's wrapping of select puzzling as a whole. It is with the select wrapper where the problem may lie.
Okay, now I know how to reproduce it. But what seems troublesome is that because my machine is slower, I need a longer timer or the stty call gets interrupted. So I go back to the other question. Do you wiggle the corners often or are you doing it to try to solve a problem you know exists even though it may not be encountered through normal use?
On further testing, if 0.3 does it for you, I'll check in 0.5 which should cover most normal wiggling on even slower systems. I really have to give the corner a more-than-average shake to get it to crash. It's one of those things where I know the bug is there and I can shake it hard enough to break it. But I'm not likely to do so in my normal usage. I want to test it on a couple more systems at home before I check it in, though.
I think we can safely say that this is literally a corner case.
I am wiggling the window to test the code. Without the patch the problem might well be encountered with my fast machine in ordinary use but I cannot reproduce it in full on my slow machine even when trying hard.
If you still get the problem on a slow machine with a 0.5 second delay I think it can reasonably be called a corner case. What you say that the call to stty is "interrupted" maybe that could be solved by re-enabling interrupts after the call to mywin.getsize(), instead of before, but I have probably misunderstood what you meant.
I will fiddle with it some more tomorrow but I suspect we have gone as far as we can go within the (possible) limitations of pythons wrapping of select and curses.
Checked in 0.5 second delay because I needed to check in another fix for scrolling and master scoreboard view with odd number of viewable lines. Ironically, it was the PgUp() trick to keep master scoreboard and listwin synced up that was allowing records and cursors to take on odd values. All the more reason why I should focus on fixing the viewable area recalculation.
I am wiggling the window to test the code. Without the patch the problem might well be encountered with my fast machine in ordinary use but I cannot reproduce it in full on my slow machine even when trying hard.
If you still get the problem on a slow machine with a 0.5 second delay I think it can reasonably be called a corner case. What you say that the call to stty is "interrupted" maybe that could be solved by re-enabling interrupts after the call to mywin.getsize(), instead of before, but I have probably misunderstood what you meant.
I will fiddle with it some more tomorrow but I suspect we have gone as far as we can go within the (possible) limitations of pythons wrapping of select and curses.
Crash is here:
Code:
Traceback (most recent call last):
File "./mlbviewer.py", line 763, in <module>
curses.wrapper(mainloop, mycfg, mykeys)
File "/usr/lib/python2.7/curses/wrapper.py", line 43, in wrapper
return func(stdscr, *args, **kwds)
File "./mlbviewer.py", line 185, in mainloop
( y , x ) = mywin.getsize()
File "/home/matthew/mlb2013/MLBviewer/mlbListWin.py", line 25, in getsize
( y , x ) = os.popen('stty size', 'r').read().split()
IOError: [Errno 4] Interrupted system call
matthew@wheezy:~/mlb2013$
Normal wiggling doesn't do it. I have to give that corner a good shake to get that to happen. I don't think there's much I can do for that one. Anyway, if 0.5 second fixes your normal use, I don't want to spend anymore time on this.
EDIT: Removed the babbling and put it into the code.
SVN revision 458: aligned the cursors, added a config option for resizing
Implemented the cursor alignment code I talked about earlier. Now listings to scoreboard, scoreboard to listings, line score to scoreboard, etc should all retain cursor position.
Also removed the PgUp() trick on resize so you can resize the scoreboard and retain your cursor position. The nifty trick here is to start with a default 24x80 screen and highlight the last game in the listings. Switch to scoreboard and you should see that you are automatically scrolled to the next page. Now pull the bottom corner until all scores are on one page.
Added a config option called wiggle_timer. Since your machine may be faster or slower than mine, increase or decrease the wiggle_timer (takes float values so you can tune it as aggressively as you want) to match your system. Default is 0.5 but I may actually change this to 1.0 since my default home laptop seems happier with 1.0 than 0.5. Now my work virtual machine is quite a bit faster because it can handle 0.5 with all but the most aggressive corner wiggling. I'll test it on a few more laptops I have and see what values work best.
(Side note: my cable provider has been awful lately so it's exposing a lot of URLError crashes. I have a good idea of the next set of bugs to tackle. )
Traceback (most recent call last):
File "./mlbviewer.py", line 763, in <module>
curses.wrapper(mainloop, mycfg, mykeys)
File "/usr/lib/python2.7/curses/wrapper.py", line 43, in wrapper
return func(stdscr, *args, **kwds)
File "./mlbviewer.py", line 185, in mainloop
( y , x ) = mywin.getsize()
File "/home/matthew/mlb2013/MLBviewer/mlbListWin.py", line 25, in getsize
( y , x ) = os.popen('stty size', 'r').read().split()
IOError: [Errno 4] Interrupted system call
matthew@wheezy:~/mlb2013$
Normal wiggling doesn't do it. I have to give that corner a good shake to get that to happen. I don't think there's much I can do for that one. Anyway, if 0.5 second fixes your normal use, I don't want to spend anymore time on this.
I cannot reproduce this but if the signal causing the interrupt is SIGWINCH then moving:
( y , x ) = mywin.getsize()
up a line, so that it is above
signal.signal(signal.SIGWINCH, donothing)
will deal with it. When the signal handler is set to SIG_IGN, SIGWINCH will be ignored and discarded and blocking system functions will not be made to return with EINTR (including select(), which is what enables the interrupt throttling to work). When the signal handler is set to donothing(), donothing() doesn't execute anything, but blocking system functions will return with EINTR.
I cannot reproduce this but if the signal causing the interrupt is SIGWINCH then moving:
( y , x ) = mywin.getsize()
up a line, so that it is above
signal.signal(signal.SIGWINCH, donothing)
will deal with it. When the signal handler is set to SIG_IGN, SIGWINCH will be ignored and discarded and blocking system functions will not be made to return with EINTR (including select(), which is what enables the interrupt throttling to work). When the signal handler is set to donothing(), donothing() doesn't execute anything, but blocking system functions will return with EINTR.
That appears to have fixed it. Making this change and leaving wiggle_timer default of 0.5, I can no longer reproduce it on main home laptop. Checked in the change and will try again on work VM tomorrow (later today.)
That appears to have fixed it. Making this change and leaving wiggle_timer default of 0.5, I can no longer reproduce it on main home laptop. Checked in the change and will try again on work VM tomorrow (later today.)
That's great. As an experiment I have caused all SIGWINCH interrupts in mlbviewer.py to be discarded everywhere except in select(): in other words, the interrupt handler is set as donothing() just before entering select, and then set to SIG_IGN as soon as it comes out (either when entering the exception handler's else block or before calling getch() where select has unblocked on keyboard input). Without the interrupt throttling, the program still misbehaves under a SIGWINCH storm. This seems to me to show pretty definitely that the problem is with the way python wraps select when receiving interrupt storms.
I don't suggest you reconfigure the code in this way in the release version of mlbviewer.py, because an ambidextrous user who both pressed a key and resized the window at the same time could lose the window redraw if the race went against her.
So I think the solution now adopted is probably the best that can be achieved, unless something else occurs to me.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.