Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1111)

Unified Diff: Parser/myreadline.c

Issue 18597: On Windows sys.stdin.readline() doesn't handle Ctrl-C properly
Patch Set: Created 3 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
--- a/Parser/myreadline.c Wed Mar 09 15:02:31 2016 +0100
+++ b/Parser/myreadline.c Fri Mar 11 05:59:02 2016 -0600
@@ -13,9 +13,9 @@
#ifdef MS_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
+extern int winerror_to_errno(int);
#endif /* MS_WINDOWS */
-
PyThreadState* _PyOS_ReadlineTState;
#ifdef WITH_THREAD
@@ -25,58 +25,89 @@
int (*PyOS_InputHook)(void) = NULL;
+#ifdef MS_WINDOWS
+static int
+my_cgets(char *buf, int len, int *nRead, HANDLE hInput)
+{
+ DWORD lasterr, consoleMode;
+
+ if (ReadConsoleA(hInput, buf, len - 1, nRead, NULL) &&
+ *nRead > 0) {
+ if (*buf == '\x1a' &&
+ GetConsoleMode(hInput, &consoleMode) &&
+ consoleMode & ENABLE_PROCESSED_INPUT) {
+ *nRead = 0;
+ } else
+ buf[*nRead] = '\0';
+ return 0;
+ }
+ lasterr = GetLastError();
+ if (lasterr != ERROR_OPERATION_ABORTED) {
+ errno = winerror_to_errno(lasterr);
+ } else {
+ /* N.B. Ctrl+C or Ctrl+Break anywhere on the line sets the last
+ error to ERROR_OPERATION_ABORTED. Under normal circumstances
+ this also causes the SIGINT or SIGBREAK handler to fire, which
+ sets 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 to provide some
+ semblance of synchronization.
+
+ BUGBUG: the event is not set for SIGBREAK.
+ BUGBUG: resetting the event should be implemented in
+ PyErr_CheckSignals, specifically by calling a
+ new untrip_signal() function.
+ */
+ HANDLE hInterruptEvent = _PyOS_SigintEvent();
+ errno = EINTR;
+ switch (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE)) {
+ case WAIT_OBJECT_0:
+ ResetEvent(hInterruptEvent);
+ }
+ }
+ return errno;
+}
+#endif /* MS_WINDOWS */
+
+
/* This function restarts a fgets() after an EINTR error occurred
except if PyOS_InterruptOccurred() returns true. */
static int
my_fgets(char *buf, int len, FILE *fp)
{
-#ifdef MS_WINDOWS
- HANDLE hInterruptEvent;
-#endif
- char *p;
int err;
while (1) {
if (PyOS_InputHook != NULL)
(void)(PyOS_InputHook)();
errno = 0;
clearerr(fp);
- if (_PyVerify_fd(fileno(fp)))
- p = fgets(buf, len, fp);
- else
- p = NULL;
- if (p != NULL)
- return 0; /* No error */
+ if (_PyVerify_fd(fileno(fp))) {
+#ifdef MS_WINDOWS
+ DWORD consoleMode;
+ HANDLE hInput = (HANDLE)_get_osfhandle(fileno(fp));
+ if (GetConsoleMode(hInput, &consoleMode)) {
+ int nRead;
+ err = my_cgets(buf, len, &nRead, hInput);
+ if (!err) {
+ if (nRead)
+ return 0; /* Success */
+ return -1; /* EOF */
+ }
+ goto check_signals;
+ }
+#endif /* MS_WINDOWS */
+ if (fgets(buf, len, fp))
+ return 0; /* Success */
+ }
err = errno;
-#ifdef MS_WINDOWS
- /* 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) {
- hInterruptEvent = _PyOS_SigintEvent();
- switch (WaitForSingleObjectEx(hInterruptEvent, 10, FALSE)) {
- case WAIT_OBJECT_0:
- ResetEvent(hInterruptEvent);
- return 1; /* Interrupt */
- case WAIT_FAILED:
- return -2; /* Error */
- }
- }
-#endif /* MS_WINDOWS */
if (feof(fp)) {
clearerr(fp);
return -1; /* EOF */
}
+check_signals:
#ifdef EINTR
if (err == EINTR) {
int s;
@@ -88,17 +119,15 @@
PyEval_SaveThread();
#endif
if (s < 0)
- return 1;
- /* try again */
+ return 1; /* Interrupt */
continue;
}
#endif
- if (PyOS_InterruptOccurred()) {
+ if (PyOS_InterruptOccurred())
return 1; /* Interrupt */
- }
return -2; /* Error */
}
- /* NOTREACHED */
+ /* NOT REACHED */
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+