summaryrefslogtreecommitdiffstats
path: root/Parser
diff options
context:
space:
mode:
authorTim Golden <mail@timgolden.me.uk>2012-06-29 17:39:26 (GMT)
committerTim Golden <mail@timgolden.me.uk>2012-06-29 17:39:26 (GMT)
commit9175c3d804ad708c1065ce85575506992fe10543 (patch)
tree04797d8de51f8b7da89ac55303c8f7f482d4f066 /Parser
parent25652884b452142460f5868ac28af4f12895e046 (diff)
downloadcpython-9175c3d804ad708c1065ce85575506992fe10543.zip
cpython-9175c3d804ad708c1065ce85575506992fe10543.tar.gz
cpython-9175c3d804ad708c1065ce85575506992fe10543.tar.bz2
Issue #1677: Handle better a race condition between the interactive interpreter and
the Ctrl-C signal handler on Windows
Diffstat (limited to 'Parser')
-rw-r--r--Parser/myreadline.c45
1 files changed, 22 insertions, 23 deletions
diff --git a/Parser/myreadline.c b/Parser/myreadline.c
index cb1cf0f..d864623 100644
--- a/Parser/myreadline.c
+++ b/Parser/myreadline.c
@@ -35,6 +35,9 @@ int (*PyOS_InputHook)(void) = NULL;
static int
my_fgets(char *buf, int len, FILE *fp)
{
+#ifdef MS_WINDOWS
+ HANDLE hInterruptEvent;
+#endif
char *p;
int err;
while (1) {
@@ -50,32 +53,28 @@ 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 which will have set the event object returned by
+ _PyOS_SigintEvent. This signal fires in another thread and
+ is not guaranteed to have occurred before this point in the
+ code.
+
+ Therefore: check whether the event is set with a small timeout.
+ If it is, assume this is a Ctrl-C and reset the event. If it
+ isn't set assume that this is a Ctrl-Z on its own 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).
- */
- Sleep(1);
- if (PyOS_InterruptOccurred()) {
+ hInterruptEvent = _PyOS_SigintEvent();
+ switch (WaitForSingleObject(hInterruptEvent, 10)) {
+ case WAIT_OBJECT_0:
+ ResetEvent(hInterruptEvent);
return 1; /* Interrupt */
+ case WAIT_FAILED:
+ return -2; /* Error */
}
- /* 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)) {
@@ -94,7 +93,7 @@ my_fgets(char *buf, int len, FILE *fp)
#endif
if (s < 0)
return 1;
- /* try again */
+ /* try again */
continue;
}
#endif