summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Golden <mail@timgolden.me.uk>2012-06-29 17:27:08 (GMT)
committerTim Golden <mail@timgolden.me.uk>2012-06-29 17:27:08 (GMT)
commitb92b757eed4aeac9b238f1fa355038e200e9e0d3 (patch)
treec82134c14af25477b366c4880dc38eca5d252de5
parent5b5619f717be2a712c05d6c63a0ca4184f263aee (diff)
downloadcpython-b92b757eed4aeac9b238f1fa355038e200e9e0d3.zip
cpython-b92b757eed4aeac9b238f1fa355038e200e9e0d3.tar.gz
cpython-b92b757eed4aeac9b238f1fa355038e200e9e0d3.tar.bz2
Issue #1677: Handle better a race condition between the interactive interpreter and
the Ctrl-C signal handler on Windows
-rw-r--r--Parser/myreadline.c37
1 files changed, 15 insertions, 22 deletions
diff --git a/Parser/myreadline.c b/Parser/myreadline.c
index cb1cf0f..f0b51f8 100644
--- a/Parser/myreadline.c
+++ b/Parser/myreadline.c
@@ -36,6 +36,7 @@ static int
my_fgets(char *buf, int len, FILE *fp)
{
char *p;
+ int i;
int err;
while (1) {
if (PyOS_InputHook != NULL)
@@ -50,32 +51,24 @@ my_fgets(char *buf, int len, FILE *fp)
return 0; /* No error */
err = errno;
#ifdef MS_WINDOWS
- /* In the case of a Ctrl+C or some other external event
- interrupting the operation:
- Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32
- error code (and feof() returns TRUE).
- Win9x: Ctrl+C seems to have no effect on fgets() returning
- early - the signal handler is called, but the fgets()
- only returns "normally" (ie, when Enter hit or feof())
+ /* Ctrl-C anywhere on the line or Ctrl-Z if the only character
+ on a line will set ERROR_OPERATION_ABORTED. Under normal
+ circumstances Ctrl-C will also have caused the SIGINT handler
+ to fire. This signal fires in another thread and is not
+ guaranteed to have occurred before this point in the code.
+
+ Therefore: check in a small loop to see if the trigger has
+ fired, in which case assume this is a Ctrl-C event. If it
+ hasn't fired within 10ms assume that this is a Ctrl-Z on its
+ own or that the signal isn't going to fire for some other
+ reason and drop through to check for EOF.
*/
if (GetLastError()==ERROR_OPERATION_ABORTED) {
- /* Signals come asynchronously, so we sleep a brief
- moment before checking if the handler has been
- triggered (we cant just return 1 before the
- signal handler has been called, as the later
- signal may be treated as a separate interrupt).
- */
+ for (i = 0; i < 10; i++) {
+ if (PyOS_InterruptOccurred())
+ return 1;
Sleep(1);
- if (PyOS_InterruptOccurred()) {
- return 1; /* Interrupt */
}
- /* Either the sleep wasn't long enough (need a
- short loop retrying?) or not interrupted at all
- (in which case we should revisit the whole thing!)
- Logging some warning would be nice. assert is not
- viable as under the debugger, the various dialogs
- mean the condition is not true.
- */
}
#endif /* MS_WINDOWS */
if (feof(fp)) {