@@ -609,7 +609,12 @@ err_iterbuffered(void)
609609return NULL;
610610}
611611612-static void drop_readahead(PyFileObject *);
612+static void
613+drop_file_readahead(PyFileObject *f)
614+{
615+PyMem_FREE(f->f_buf);
616+f->f_buf = NULL;
617+}
613618614619/* Methods */
615620@@ -632,7 +637,7 @@ file_dealloc(PyFileObject *f)
632637Py_XDECREF(f->f_mode);
633638Py_XDECREF(f->f_encoding);
634639Py_XDECREF(f->f_errors);
635-drop_readahead(f);
640+drop_file_readahead(f);
636641Py_TYPE(f)->tp_free((PyObject *)f);
637642}
638643@@ -767,13 +772,7 @@ file_seek(PyFileObject *f, PyObject *args)
767772768773if (f->f_fp == NULL)
769774return err_closed();
770-if (f->unlocked_count > 0) {
771-PyErr_SetString(PyExc_IOError,
772-"seek() called during concurrent "
773-"operation on the same file object");
774-return NULL;
775- }
776-drop_readahead(f);
775+drop_file_readahead(f);
777776whence = 0;
778777if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &whence))
779778return NULL;
@@ -2242,49 +2241,51 @@ static PyGetSetDef file_getsetlist[] = {
22422241 {0},
22432242};
224422432244+typedef struct {
2245+char *buf, *bufptr, *bufend;
2246+} readaheadbuffer;
2247+22452248static void
2246-drop_readahead(PyFileObject *f)
2249+drop_readaheadbuffer(readaheadbuffer *rab)
22472250{
2248-if (f->f_buf != NULL) {
2249-PyMem_Free(f->f_buf);
2250-f->f_buf = NULL;
2251+if (rab->buf != NULL) {
2252+PyMem_FREE(rab->buf);
2253+rab->buf = NULL;
22512254 }
22522255}
2253225622542257/* Make sure that file has a readahead buffer with at least one byte
22552258 (unless at EOF) and no more than bufsize. Returns negative value on
22562259 error, will set MemoryError if bufsize bytes cannot be allocated. */
22572260static int
2258-readahead(PyFileObject *f, Py_ssize_t bufsize)
2261+readahead(PyFileObject *f, readaheadbuffer *rab, Py_ssize_t bufsize)
22592262{
22602263Py_ssize_t chunksize;
226122642262-assert(f->unlocked_count == 0);
2263-if (f->f_buf != NULL) {
2264-if( (f->f_bufend - f->f_bufptr) >= 1)
2265+if (rab->buf != NULL) {
2266+if ((rab->bufend - rab->bufptr) >= 1)
22652267return 0;
22662268else
2267-drop_readahead(f);
2269+drop_readaheadbuffer(rab);
22682270 }
2269-if ((f->f_buf = (char *)PyMem_Malloc(bufsize)) == NULL) {
2271+if ((rab->buf = PyMem_MALLOC(bufsize)) == NULL) {
22702272PyErr_NoMemory();
22712273return -1;
22722274 }
22732275FILE_BEGIN_ALLOW_THREADS(f)
22742276errno = 0;
2275-chunksize = Py_UniversalNewlineFread(
2276-f->f_buf, bufsize, f->f_fp, (PyObject *)f);
2277+chunksize = Py_UniversalNewlineFread(rab->buf, bufsize, f->f_fp, (PyObject *)f);
22772278FILE_END_ALLOW_THREADS(f)
22782279if (chunksize == 0) {
22792280if (ferror(f->f_fp)) {
22802281PyErr_SetFromErrno(PyExc_IOError);
22812282clearerr(f->f_fp);
2282-drop_readahead(f);
2283+drop_readaheadbuffer(rab);
22832284return -1;
22842285 }
22852286 }
2286-f->f_bufptr = f->f_buf;
2287-f->f_bufend = f->f_buf + chunksize;
2287+rab->bufptr = rab->buf;
2288+rab->bufend = rab->buf + chunksize;
22882289return 0;
22892290}
22902291@@ -2294,51 +2295,43 @@ readahead(PyFileObject *f, Py_ssize_t bufsize)
22942295 logarithmic buffer growth to about 50 even when reading a 1gb line. */
2295229622962297static PyStringObject *
2297-readahead_get_line_skip(PyFileObject *f, Py_ssize_t skip, Py_ssize_t bufsize)
2298+readahead_get_line_skip(PyFileObject *f, readaheadbuffer *rab, Py_ssize_t skip, Py_ssize_t bufsize)
22982299{
22992300PyStringObject* s;
23002301char *bufptr;
23012302char *buf;
23022303Py_ssize_t len;
230323042304-if (f->unlocked_count > 0) {
2305-PyErr_SetString(PyExc_IOError,
2306-"next() called during concurrent "
2307-"operation on the same file object");
2308-return NULL;
2309- }
2310-if (f->f_buf == NULL)
2311-if (readahead(f, bufsize) < 0)
2305+if (rab->buf == NULL)
2306+if (readahead(f, rab, bufsize) < 0)
23122307return NULL;
231323082314-len = f->f_bufend - f->f_bufptr;
2309+len = rab->bufend - rab->bufptr;
23152310if (len == 0)
2316-return (PyStringObject *)
2317-PyString_FromStringAndSize(NULL, skip);
2318-bufptr = (char *)memchr(f->f_bufptr, '\n', len);
2311+return (PyStringObject *)PyString_FromStringAndSize(NULL, skip);
2312+bufptr = (char *)memchr(rab->bufptr, '\n', len);
23192313if (bufptr != NULL) {
23202314bufptr++; /* Count the '\n' */
2321-len = bufptr - f->f_bufptr;
2322-s = (PyStringObject *)
2323-PyString_FromStringAndSize(NULL, skip + len);
2315+len = bufptr - rab->bufptr;
2316+s = (PyStringObject *)PyString_FromStringAndSize(NULL, skip + len);
23242317if (s == NULL)
23252318return NULL;
2326-memcpy(PyString_AS_STRING(s) + skip, f->f_bufptr, len);
2327-f->f_bufptr = bufptr;
2328-if (bufptr == f->f_bufend)
2329-drop_readahead(f);
2319+memcpy(PyString_AS_STRING(s) + skip, rab->bufptr, len);
2320+rab->bufptr = bufptr;
2321+if (bufptr == rab->bufend)
2322+drop_readaheadbuffer(rab);
23302323 } else {
2331-bufptr = f->f_bufptr;
2332-buf = f->f_buf;
2333-f->f_buf = NULL; /* Force new readahead buffer */
2324+bufptr = rab->bufptr;
2325+buf = rab->buf;
2326+rab->buf = NULL; /* Force new readahead buffer */
23342327assert(len <= PY_SSIZE_T_MAX - skip);
2335-s = readahead_get_line_skip(f, skip + len, bufsize + (bufsize>>2));
2328+s = readahead_get_line_skip(f, rab, skip + len, bufsize + (bufsize>>2));
23362329if (s == NULL) {
2337-PyMem_Free(buf);
2330+PyMem_FREE(buf);
23382331return NULL;
23392332 }
23402333memcpy(PyString_AS_STRING(s) + skip, bufptr, len);
2341-PyMem_Free(buf);
2334+PyMem_FREE(buf);
23422335 }
23432336return s;
23442337}
@@ -2356,7 +2349,30 @@ file_iternext(PyFileObject *f)
23562349if (!f->readable)
23572350return err_mode("reading");
235823512359-l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE);
2352+ {
2353+/*
2354+ Multiple threads can enter this method while the GIL is released
2355+ during file read and wreak havoc on the file object's readahead
2356+ buffer. To avoid dealing with cross-thread coordination issues, we
2357+ cache the file buffer state locally and only set it back on the file
2358+ object when we're done.
2359+ */
2360+readaheadbuffer rab = {f->f_buf, f->f_bufptr, f->f_bufend};
2361+f->f_buf = NULL;
2362+l = readahead_get_line_skip(f, &rab, 0, READAHEAD_BUFSIZE);
2363+/*
2364+ Make sure the file's internal read buffer is cleared out. This will
2365+ only do anything if some other thread interleaved with us during
2366+ readahead. We want to drop any changeling buffer, so we don't leak
2367+ memory. We may lose data, but that's what you get for reading the same
2368+ file object in multiple threads.
2369+ */
2370+drop_file_readahead(f);
2371+f->f_buf = rab.buf;
2372+f->f_bufptr = rab.bufptr;
2373+f->f_bufend = rab.bufend;
2374+ }
2375+23602376if (l == NULL || PyString_GET_SIZE(l) == 0) {
23612377Py_XDECREF(l);
23622378return NULL;