Index: Include/fileobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/fileobject.h,v retrieving revision 2.31 diff -c -r2.31 fileobject.h *** Include/fileobject.h 12 Aug 2002 07:21:56 -0000 2.31 --- Include/fileobject.h 20 Aug 2002 20:45:40 -0000 *************** *** 7,12 **** --- 7,14 ---- extern "C" { #endif + #include "pythread.h" + typedef struct { PyObject_HEAD FILE *f_fp; *************** *** 19,24 **** --- 21,27 ---- char* f_buf; /* Allocated readahead buffer */ char* f_bufend; /* Points after last occupied position */ char* f_bufptr; /* Current buffer position */ + PyThread_type_lock f_lock; /* Lock to protect f_fp */ #ifdef WITH_UNIVERSAL_NEWLINES int f_univ_newline; /* Handle any newline convention */ int f_newlinetypes; /* Types of newlines seen */ *************** *** 31,36 **** --- 34,42 ---- #define PyFile_Check(op) PyObject_TypeCheck(op, &PyFile_Type) #define PyFile_CheckExact(op) ((op)->ob_type == &PyFile_Type) + #define PyFile_LOCK(F) PyThread_acquire_lock((F)->f_lock, 1) + #define PyFile_UNLOCK(F) PyThread_release_lock((F)->f_lock) + PyAPI_FUNC(PyObject *) PyFile_FromString(char *, char *); PyAPI_FUNC(void) PyFile_SetBufSize(PyObject *, int); PyAPI_FUNC(PyObject *) PyFile_FromFile(FILE *, char *, char *, *************** *** 54,65 **** */ #define PY_STDIOTEXTMODE "b" char *Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *); ! size_t Py_UniversalNewlineFread(char *, size_t, FILE *, PyObject *); #else #define PY_STDIOTEXTMODE "" #define Py_UniversalNewlineFgets(buf, len, fp, obj) fgets((buf), (len), (fp)) ! #define Py_UniversalNewlineFread(buf, len, fp, obj) \ ! fread((buf), 1, (len), (fp)) #endif /* WITH_UNIVERSAL_NEWLINES */ #ifdef __cplusplus } --- 60,71 ---- */ #define PY_STDIOTEXTMODE "b" char *Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *); ! size_t Py_UniversalNewlineFread(char *, size_t, PyObject *); #else #define PY_STDIOTEXTMODE "" #define Py_UniversalNewlineFgets(buf, len, fp, obj) fgets((buf), (len), (fp)) ! #define Py_UniversalNewlineFread(buf, len, obj) \ ! fread((buf), 1, (len), (((PyFileObject *)(obj))->f_fp)) #endif /* WITH_UNIVERSAL_NEWLINES */ #ifdef __cplusplus } Index: Objects/fileobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/fileobject.c,v retrieving revision 2.168 diff -c -r2.168 fileobject.c *** Objects/fileobject.c 14 Aug 2002 21:01:41 -0000 2.168 --- Objects/fileobject.c 20 Aug 2002 20:45:40 -0000 *************** *** 54,59 **** --- 54,82 ---- #define NEWLINE_CRLF 4 /* \r\n newline seen */ #endif + static PyObject *err_closed(void); + + #define ACQUIRE_FILE_LOCK(F) \ + Py_BEGIN_ALLOW_THREADS \ + PyFile_LOCK(F); \ + + #define ACQUIRE_FILE_LOCK_CHECK(F) \ + Py_BEGIN_ALLOW_THREADS \ + PyFile_LOCK(F); \ + if ((F)->f_fp == NULL) { \ + PyFile_UNLOCK(F); \ + Py_BLOCK_THREADS \ + return err_closed(); \ + } + + #define RELEASE_FILE_LOCK(F) \ + PyFile_UNLOCK(F); \ + Py_END_ALLOW_THREADS + + #define RELEASE_FILE_LOCK_SUB(F) \ + PyFile_UNLOCK(F); \ + Py_BLOCK_THREADS + FILE * PyFile_AsFile(PyObject *f) { *************** *** 81,88 **** { #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) struct stat buf; ! if (f->f_fp == NULL) return f; if (fstat(fileno(f->f_fp), &buf) == 0 && S_ISDIR(buf.st_mode)) { #ifdef HAVE_STRERROR --- 104,115 ---- { #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) struct stat buf; ! ! ACQUIRE_FILE_LOCK(f) ! if (f->f_fp == NULL) { ! RELEASE_FILE_LOCK_SUB(f) return f; + } if (fstat(fileno(f->f_fp), &buf) == 0 && S_ISDIR(buf.st_mode)) { #ifdef HAVE_STRERROR *************** *** 90,101 **** #else char *msg = "Is a directory"; #endif ! PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(is)", ! EISDIR, msg); PyErr_SetObject(PyExc_IOError, exc); return NULL; } #endif return f; } --- 117,131 ---- #else char *msg = "Is a directory"; #endif ! PyObject *exc; ! RELEASE_FILE_LOCK_SUB(f) ! exc = PyObject_CallFunction(PyExc_IOError, ! "(is)", EISDIR, msg); PyErr_SetObject(PyExc_IOError, exc); return NULL; } #endif + RELEASE_FILE_LOCK(f) return f; } *************** *** 125,131 **** --- 155,163 ---- if (f->f_name == NULL || f->f_mode == NULL) return NULL; + ACQUIRE_FILE_LOCK(f); f->f_fp = fp; + RELEASE_FILE_LOCK(f); f = dircheck(f); return (PyObject *) f; } *************** *** 133,138 **** --- 165,171 ---- static PyObject * open_the_file(PyFileObject *f, char *name, char *mode) { + int fp_null = 0; assert(f != NULL); assert(PyFile_Check(f)); assert(name != NULL); *************** *** 156,162 **** else #endif { ! Py_BEGIN_ALLOW_THREADS #ifdef WITH_UNIVERSAL_NEWLINES if (strcmp(mode, "U") == 0 || strcmp(mode, "rU") == 0) mode = "rb"; --- 189,195 ---- else #endif { ! ACQUIRE_FILE_LOCK(f) #ifdef WITH_UNIVERSAL_NEWLINES if (strcmp(mode, "U") == 0 || strcmp(mode, "rU") == 0) mode = "rb"; *************** *** 169,177 **** mode = "r"; #endif f->f_fp = fopen(name, mode); ! Py_END_ALLOW_THREADS } ! if (f->f_fp == NULL) { #ifdef NO_FOPEN_ERRNO /* Metroworks only, wich does not always sets errno */ if (errno == 0) { --- 202,211 ---- mode = "r"; #endif f->f_fp = fopen(name, mode); ! fp_null = f->f_fp ? 0 : 1; ! RELEASE_FILE_LOCK(f) } ! if (fp_null) { #ifdef NO_FOPEN_ERRNO /* Metroworks only, wich does not always sets errno */ if (errno == 0) { *************** *** 256,267 **** --- 290,303 ---- default: type = _IOFBF; } + ACQUIRE_FILE_LOCK((PyFileObject *)f) setvbuf(((PyFileObject *)f)->f_fp, (char *)NULL, type, bufsize); #else /* !HAVE_SETVBUF */ if (bufsize <= 1) setbuf(((PyFileObject *)f)->f_fp, (char *)NULL); #endif /* !HAVE_SETVBUF */ + RELEASE_FILE_LOCK((PyFileObject *)f) } } *************** *** 279,289 **** static void file_dealloc(PyFileObject *f) { if (f->f_fp != NULL && f->f_close != NULL) { - Py_BEGIN_ALLOW_THREADS (*f->f_close)(f->f_fp); - Py_END_ALLOW_THREADS } Py_XDECREF(f->f_name); Py_XDECREF(f->f_mode); drop_readahead(f); --- 315,325 ---- static void file_dealloc(PyFileObject *f) { + ACQUIRE_FILE_LOCK(f) if (f->f_fp != NULL && f->f_close != NULL) { (*f->f_close)(f->f_fp); } + RELEASE_FILE_LOCK(f) Py_XDECREF(f->f_name); Py_XDECREF(f->f_mode); drop_readahead(f); *************** *** 293,300 **** static PyObject * file_repr(PyFileObject *f) { return PyString_FromFormat("<%s file '%s', mode '%s' at %p>", ! f->f_fp == NULL ? "closed" : "open", PyString_AsString(f->f_name), PyString_AsString(f->f_mode), f); --- 329,343 ---- static PyObject * file_repr(PyFileObject *f) { + int is_open; + + /* XXX perhaps this is a harmless data race */ + ACQUIRE_FILE_LOCK(f) + is_open = f->f_fp ? 1 : 0; + RELEASE_FILE_LOCK(f) + return PyString_FromFormat("<%s file '%s', mode '%s' at %p>", ! is_open ? "open" : "closed", PyString_AsString(f->f_name), PyString_AsString(f->f_mode), f); *************** *** 304,318 **** file_close(PyFileObject *f) { int sts = 0; ! if (f->f_fp != NULL) { ! if (f->f_close != NULL) { ! Py_BEGIN_ALLOW_THREADS ! errno = 0; ! sts = (*f->f_close)(f->f_fp); ! Py_END_ALLOW_THREADS ! } ! f->f_fp = NULL; } if (sts == EOF) return PyErr_SetFromErrno(PyExc_IOError); if (sts != 0) --- 347,359 ---- file_close(PyFileObject *f) { int sts = 0; ! ACQUIRE_FILE_LOCK(f) ! if (f->f_fp != NULL && f->f_close != NULL) { ! errno = 0; ! sts = (*f->f_close)(f->f_fp); } + f->f_fp = NULL; + RELEASE_FILE_LOCK(f) if (sts == EOF) return PyErr_SetFromErrno(PyExc_IOError); if (sts != 0) *************** *** 407,414 **** Py_off_t offset; PyObject *offobj; - if (f->f_fp == NULL) - return err_closed(); drop_readahead(f); whence = 0; if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &whence)) --- 448,453 ---- *************** *** 422,435 **** if (PyErr_Occurred()) return NULL; ! Py_BEGIN_ALLOW_THREADS errno = 0; ret = _portable_fseek(f->f_fp, offset, whence); ! Py_END_ALLOW_THREADS ! if (ret != 0) { PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); return NULL; } #ifdef WITH_UNIVERSAL_NEWLINES --- 461,475 ---- if (PyErr_Occurred()) return NULL; ! ACQUIRE_FILE_LOCK_CHECK(f) errno = 0; ret = _portable_fseek(f->f_fp, offset, whence); ! if (ret) ! clearerr(f->f_fp); ! RELEASE_FILE_LOCK(f) ! if (ret) { PyErr_SetFromErrno(PyExc_IOError); return NULL; } #ifdef WITH_UNIVERSAL_NEWLINES *************** *** 448,455 **** Py_off_t newsize; PyObject *newsizeobj; - if (f->f_fp == NULL) - return err_closed(); newsizeobj = NULL; if (!PyArg_ParseTuple(args, "|O:truncate", &newsizeobj)) return NULL; --- 488,493 ---- *************** *** 469,487 **** } else { /* Default to current position. */ ! Py_BEGIN_ALLOW_THREADS errno = 0; newsize = _portable_ftell(f->f_fp); ! Py_END_ALLOW_THREADS if (newsize == -1) goto onioerror; } /* Flush the file. */ ! Py_BEGIN_ALLOW_THREADS errno = 0; ret = fflush(f->f_fp); ! Py_END_ALLOW_THREADS if (ret != 0) goto onioerror; --- 507,525 ---- } else { /* Default to current position. */ ! ACQUIRE_FILE_LOCK_CHECK(f) errno = 0; newsize = _portable_ftell(f->f_fp); ! RELEASE_FILE_LOCK(f) if (newsize == -1) goto onioerror; } /* Flush the file. */ ! ACQUIRE_FILE_LOCK_CHECK(f) errno = 0; ret = fflush(f->f_fp); ! RELEASE_FILE_LOCK(f) if (ret != 0) goto onioerror; *************** *** 497,523 **** if (newsizeobj == NULL) current = newsize; else { ! Py_BEGIN_ALLOW_THREADS errno = 0; current = _portable_ftell(f->f_fp); ! Py_END_ALLOW_THREADS if (current == -1) goto onioerror; } /* Move to newsize. */ if (current != newsize) { ! Py_BEGIN_ALLOW_THREADS errno = 0; error = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0; ! Py_END_ALLOW_THREADS if (error) goto onioerror; } /* Truncate. Note that this may grow the file! */ ! Py_BEGIN_ALLOW_THREADS errno = 0; hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp)); error = hFile == (HANDLE)-1; --- 535,561 ---- if (newsizeobj == NULL) current = newsize; else { ! ACQUIRE_FILE_LOCK(f) errno = 0; current = _portable_ftell(f->f_fp); ! RELEASE_FILE_LOCK(f) if (current == -1) goto onioerror; } /* Move to newsize. */ if (current != newsize) { ! ACQUIRE_FILE_LOCK(f) errno = 0; error = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0; ! RELEASE_FILE_LOCK(f) if (error) goto onioerror; } /* Truncate. Note that this may grow the file! */ ! ACQUIRE_FILE_LOCK(f) errno = 0; hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp)); error = hFile == (HANDLE)-1; *************** *** 526,551 **** if (error) errno = EACCES; } ! Py_END_ALLOW_THREADS if (error) goto onioerror; /* Restore original file position. */ if (current != newsize) { ! Py_BEGIN_ALLOW_THREADS errno = 0; error = _portable_fseek(f->f_fp, current, SEEK_SET) != 0; ! Py_END_ALLOW_THREADS if (error) goto onioerror; } } #else ! Py_BEGIN_ALLOW_THREADS errno = 0; ret = ftruncate(fileno(f->f_fp), newsize); ! Py_END_ALLOW_THREADS if (ret != 0) goto onioerror; #endif /* !MS_WINDOWS */ --- 564,589 ---- if (error) errno = EACCES; } ! RELEASE_FILE_LOCK(f) if (error) goto onioerror; /* Restore original file position. */ if (current != newsize) { ! ACQUIRE_FILE_LOCK(f) errno = 0; error = _portable_fseek(f->f_fp, current, SEEK_SET) != 0; ! RELEASE_FILE_LOCK(f) if (error) goto onioerror; } } #else ! ACQUIRE_FILE_LOCK(f) errno = 0; ret = ftruncate(fileno(f->f_fp), newsize); ! RELEASE_FILE_LOCK(f) if (ret != 0) goto onioerror; #endif /* !MS_WINDOWS */ *************** *** 554,560 **** --- 592,600 ---- onioerror: PyErr_SetFromErrno(PyExc_IOError); + ACQUIRE_FILE_LOCK(f) clearerr(f->f_fp); + RELEASE_FILE_LOCK(f) return NULL; } #endif /* HAVE_FTRUNCATE */ *************** *** 564,578 **** { Py_off_t pos; ! if (f->f_fp == NULL) ! return err_closed(); ! Py_BEGIN_ALLOW_THREADS errno = 0; pos = _portable_ftell(f->f_fp); ! Py_END_ALLOW_THREADS if (pos == -1) { PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); return NULL; } #ifdef WITH_UNIVERSAL_NEWLINES --- 604,617 ---- { Py_off_t pos; ! ACQUIRE_FILE_LOCK_CHECK(f) errno = 0; pos = _portable_ftell(f->f_fp); ! if (pos == -1) ! clearerr(f->f_fp); ! RELEASE_FILE_LOCK(f) if (pos == -1) { PyErr_SetFromErrno(PyExc_IOError); return NULL; } #ifdef WITH_UNIVERSAL_NEWLINES *************** *** 595,603 **** static PyObject * file_fileno(PyFileObject *f) { ! if (f->f_fp == NULL) ! return err_closed(); ! return PyInt_FromLong((long) fileno(f->f_fp)); } static PyObject * --- 634,645 ---- static PyObject * file_fileno(PyFileObject *f) { ! int fd; ! ! ACQUIRE_FILE_LOCK_CHECK(f) ! fd = fileno(f->f_fp); ! RELEASE_FILE_LOCK(f) ! return PyInt_FromLong((long) fd); } static PyObject * *************** *** 605,619 **** { int res; ! if (f->f_fp == NULL) ! return err_closed(); ! Py_BEGIN_ALLOW_THREADS errno = 0; res = fflush(f->f_fp); ! Py_END_ALLOW_THREADS ! if (res != 0) { ! PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); return NULL; } Py_INCREF(Py_None); --- 647,660 ---- { int res; ! ACQUIRE_FILE_LOCK_CHECK(f) errno = 0; res = fflush(f->f_fp); ! if (res) clearerr(f->f_fp); + RELEASE_FILE_LOCK(f) + if (res) { + PyErr_SetFromErrno(PyExc_IOError); return NULL; } Py_INCREF(Py_None); *************** *** 624,634 **** file_isatty(PyFileObject *f) { long res; ! if (f->f_fp == NULL) ! return err_closed(); ! Py_BEGIN_ALLOW_THREADS res = isatty((int)fileno(f->f_fp)); ! Py_END_ALLOW_THREADS return PyBool_FromLong(res); } --- 665,673 ---- file_isatty(PyFileObject *f) { long res; ! ACQUIRE_FILE_LOCK(f) res = isatty((int)fileno(f->f_fp)); ! RELEASE_FILE_LOCK(f) return PyBool_FromLong(res); } *************** *** 651,656 **** --- 690,696 ---- #ifdef HAVE_FSTAT off_t pos, end; struct stat st; + ACQUIRE_FILE_LOCK(f) if (fstat(fileno(f->f_fp), &st) == 0) { end = st.st_size; /* The following is not a bug: we really need to call lseek() *************** *** 673,683 **** } if (pos < 0) clearerr(f->f_fp); ! if (end > pos && pos >= 0) return currentsize + end - pos + 1; /* Add 1 so if the file were to grow we'd notice. */ } #endif if (currentsize > SMALLCHUNK) { /* Keep doubling until we reach BIGCHUNK; then keep adding BIGCHUNK. */ --- 713,726 ---- } if (pos < 0) clearerr(f->f_fp); ! if (end > pos && pos >= 0) { ! RELEASE_FILE_LOCK_SUB(f) return currentsize + end - pos + 1; + } /* Add 1 so if the file were to grow we'd notice. */ } #endif + RELEASE_FILE_LOCK(f) if (currentsize > SMALLCHUNK) { /* Keep doubling until we reach BIGCHUNK; then keep adding BIGCHUNK. */ *************** *** 696,703 **** size_t bytesread, buffersize, chunksize; PyObject *v; - if (f->f_fp == NULL) - return err_closed(); if (!PyArg_ParseTuple(args, "|l:read", &bytesrequested)) return NULL; if (bytesrequested < 0) --- 739,744 ---- *************** *** 714,729 **** return NULL; bytesread = 0; for (;;) { ! Py_BEGIN_ALLOW_THREADS errno = 0; chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread, ! buffersize - bytesread, f->f_fp, (PyObject *)f); ! Py_END_ALLOW_THREADS if (chunksize == 0) { ! if (!ferror(f->f_fp)) break; PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); Py_DECREF(v); return NULL; } --- 755,779 ---- return NULL; bytesread = 0; for (;;) { ! int err; ! ACQUIRE_FILE_LOCK_CHECK(f) errno = 0; + err = 0; chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread, ! buffersize - bytesread, (PyObject *)f); if (chunksize == 0) { ! if (ferror(f->f_fp)) { ! clearerr(f->f_fp); ! err = 1; ! } ! else { ! RELEASE_FILE_LOCK_SUB(f) break; + } + } + RELEASE_FILE_LOCK(f) + if (err) { PyErr_SetFromErrno(PyExc_IOError); Py_DECREF(v); return NULL; } *************** *** 748,769 **** int ntodo; size_t ndone, nnow; - if (f->f_fp == NULL) - return err_closed(); if (!PyArg_ParseTuple(args, "w#", &ptr, &ntodo)) return NULL; ndone = 0; while (ntodo > 0) { ! Py_BEGIN_ALLOW_THREADS errno = 0; ! nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp, (PyObject *)f); - Py_END_ALLOW_THREADS if (nnow == 0) { ! if (!ferror(f->f_fp)) ! break; PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); return NULL; } ndone += nnow; --- 798,821 ---- int ntodo; size_t ndone, nnow; if (!PyArg_ParseTuple(args, "w#", &ptr, &ntodo)) return NULL; ndone = 0; while (ntodo > 0) { ! int err; ! ACQUIRE_FILE_LOCK_CHECK(f) ! err = 0; errno = 0; ! nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, (PyObject *)f); if (nnow == 0) { ! err = ferror(f->f_fp); ! if (err) ! clearerr(f->f_fp); ! } ! RELEASE_FILE_LOCK(f) ! if (nnow == 0 && err) { PyErr_SetFromErrno(PyExc_IOError); return NULL; } ndone += nnow; *************** *** 823,829 **** #ifdef USE_FGETS_IN_GETLINE static PyObject* ! getline_via_fgets(FILE *fp) { /* INITBUFSIZE is the maximum line length that lets us get away with the fast * no-realloc, one-fgets()-call path. Boosting it isn't free, because we have --- 875,881 ---- #ifdef USE_FGETS_IN_GETLINE static PyObject* ! getline_via_fgets(PyFileObject *f) { /* INITBUFSIZE is the maximum line length that lets us get away with the fast * no-realloc, one-fgets()-call path. Boosting it isn't free, because we have *************** *** 855,869 **** total_v_size = INITBUFSIZE; /* start small and pray */ pvfree = buf; for (;;) { ! Py_BEGIN_ALLOW_THREADS pvend = buf + total_v_size; nfree = pvend - pvfree; memset(pvfree, '\n', nfree); ! p = fgets(pvfree, nfree, fp); Py_END_ALLOW_THREADS if (p == NULL) { - clearerr(fp); if (PyErr_CheckSignals()) return NULL; v = PyString_FromStringAndSize(buf, pvfree - buf); --- 907,929 ---- total_v_size = INITBUFSIZE; /* start small and pray */ pvfree = buf; for (;;) { ! Py_BEGIN_ALLOW_THREADS; ! PyFile_LOCK(f); ! if (f->f_fp == NULL) { ! PyFile_UNLOCK(f); ! Py_BLOCK_THREADS; ! return err_closed(); ! } pvend = buf + total_v_size; nfree = pvend - pvfree; memset(pvfree, '\n', nfree); ! p = fgets(pvfree, nfree, f->f_fp); ! if (p == NULL) ! clearerr(f->f_fp); ! PyFile_UNLOCK(f); Py_END_ALLOW_THREADS if (p == NULL) { if (PyErr_CheckSignals()) return NULL; v = PyString_FromStringAndSize(buf, pvfree - buf); *************** *** 929,943 **** * the code above for detailed comments about the logic. */ for (;;) { ! Py_BEGIN_ALLOW_THREADS pvend = BUF(v) + total_v_size; nfree = pvend - pvfree; memset(pvfree, '\n', nfree); ! p = fgets(pvfree, nfree, fp); Py_END_ALLOW_THREADS if (p == NULL) { - clearerr(fp); if (PyErr_CheckSignals()) { Py_DECREF(v); return NULL; --- 989,1011 ---- * the code above for detailed comments about the logic. */ for (;;) { ! Py_BEGIN_ALLOW_THREADS; ! PyFile_LOCK(f); ! if (f->f_fp == NULL) { ! PyFile_UNLOCK(f); ! Py_BLOCK_THREADS; ! return err_closed(); ! } pvend = BUF(v) + total_v_size; nfree = pvend - pvfree; memset(pvfree, '\n', nfree); ! p = fgets(pvfree, nfree, f->f_fp); ! if (p == NULL) ! clearerr(f->f_fp); ! PyFile_UNLOCK(f); Py_END_ALLOW_THREADS if (p == NULL) { if (PyErr_CheckSignals()) { Py_DECREF(v); return NULL; *************** *** 989,995 **** static PyObject * get_line(PyFileObject *f, int n) { - FILE *fp = f->f_fp; int c; char *buf, *end; size_t total_v_size; /* total # of slots in buffer */ --- 1057,1062 ---- *************** *** 1004,1014 **** #if defined(USE_FGETS_IN_GETLINE) #ifdef WITH_UNIVERSAL_NEWLINES ! if (n <= 0 && !univ_newline ) #else ! if (n <= 0) #endif ! return getline_via_fgets(fp); #endif total_v_size = n > 0 ? n : 100; v = PyString_FromStringAndSize((char *)NULL, total_v_size); --- 1071,1081 ---- #if defined(USE_FGETS_IN_GETLINE) #ifdef WITH_UNIVERSAL_NEWLINES ! if (n <= 0 && !univ_newline ) #else ! if (n <= 0) #endif ! return getline_via_fgets(f); #endif total_v_size = n > 0 ? n : 100; v = PyString_FromStringAndSize((char *)NULL, total_v_size); *************** *** 1018,1024 **** end = buf + total_v_size; for (;;) { ! Py_BEGIN_ALLOW_THREADS FLOCKFILE(fp); #ifdef WITH_UNIVERSAL_NEWLINES if (univ_newline) { --- 1085,1094 ---- end = buf + total_v_size; for (;;) { ! int err = 0; ! FILE *fp; ! ACQUIRE_FILE_LOCK_CHECK(f) ! fp = f->f_fp; FLOCKFILE(fp); #ifdef WITH_UNIVERSAL_NEWLINES if (univ_newline) { *************** *** 1055,1061 **** buf != end) ; FUNLOCKFILE(fp); ! Py_END_ALLOW_THREADS #ifdef WITH_UNIVERSAL_NEWLINES f->f_newlinetypes = newlinetypes; f->f_skipnextlf = skipnextlf; --- 1125,1136 ---- buf != end) ; FUNLOCKFILE(fp); ! if (c == EOF) { ! err = ferror(fp); ! /* XXX old code called clearerr() regardless */ ! clearerr(fp); ! } ! RELEASE_FILE_LOCK(f) #ifdef WITH_UNIVERSAL_NEWLINES f->f_newlinetypes = newlinetypes; f->f_skipnextlf = skipnextlf; *************** *** 1063,1075 **** if (c == '\n') break; if (c == EOF) { ! if (ferror(fp)) { PyErr_SetFromErrno(PyExc_IOError); - clearerr(fp); Py_DECREF(v); return NULL; } - clearerr(fp); if (PyErr_CheckSignals()) { Py_DECREF(v); return NULL; --- 1138,1148 ---- if (c == '\n') break; if (c == EOF) { ! if (err) { PyErr_SetFromErrno(PyExc_IOError); Py_DECREF(v); return NULL; } if (PyErr_CheckSignals()) { Py_DECREF(v); return NULL; *************** *** 1113,1120 **** } if (PyFile_Check(f)) { - if (((PyFileObject*)f)->f_fp == NULL) - return err_closed(); result = get_line((PyFileObject *)f, n); } else { --- 1186,1191 ---- *************** *** 1173,1180 **** { int n = -1; - if (f->f_fp == NULL) - return err_closed(); if (!PyArg_ParseTuple(args, "|i:readline", &n)) return NULL; if (n == 0) --- 1244,1249 ---- *************** *** 1201,1229 **** int err; int shortread = 0; - if (f->f_fp == NULL) - return err_closed(); if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint)) return NULL; if ((list = PyList_New(0)) == NULL) return NULL; for (;;) { if (shortread) nread = 0; else { ! Py_BEGIN_ALLOW_THREADS errno = 0; nread = Py_UniversalNewlineFread(buffer+nfilled, ! buffersize-nfilled, f->f_fp, (PyObject *)f); ! Py_END_ALLOW_THREADS shortread = (nread < buffersize-nfilled); } if (nread == 0) { sizehint = 0; ! if (!ferror(f->f_fp)) break; PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); error: Py_DECREF(list); list = NULL; --- 1270,1307 ---- int err; int shortread = 0; if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint)) return NULL; if ((list = PyList_New(0)) == NULL) return NULL; for (;;) { + int err = 0; if (shortread) nread = 0; else { ! ACQUIRE_FILE_LOCK(f) ! if (f->f_fp == NULL) { ! RELEASE_FILE_LOCK_SUB(f) ! err_closed(); ! goto error; ! } errno = 0; nread = Py_UniversalNewlineFread(buffer+nfilled, ! buffersize-nfilled, (PyObject *)f); ! if (nread == 0) { ! if (ferror(f->f_fp)) { ! err = 1; ! clearerr(f->f_fp); ! } ! } ! RELEASE_FILE_LOCK(f) shortread = (nread < buffersize-nfilled); } if (nread == 0) { sizehint = 0; ! if (!err) break; PyErr_SetFromErrno(PyExc_IOError); error: Py_DECREF(list); list = NULL; *************** *** 1311,1328 **** { char *s; int n, n2; - if (f->f_fp == NULL) - return err_closed(); if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n)) return NULL; f->f_softspace = 0; ! Py_BEGIN_ALLOW_THREADS errno = 0; n2 = fwrite(s, 1, n, f->f_fp); ! Py_END_ALLOW_THREADS if (n2 != n) { PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); return NULL; } Py_INCREF(Py_None); --- 1389,1405 ---- { char *s; int n, n2; if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n)) return NULL; f->f_softspace = 0; ! ACQUIRE_FILE_LOCK_CHECK(f) errno = 0; n2 = fwrite(s, 1, n, f->f_fp); ! if (n2 != n) ! clearerr(f->f_fp); ! RELEASE_FILE_LOCK(f) if (n2 != n) { PyErr_SetFromErrno(PyExc_IOError); return NULL; } Py_INCREF(Py_None); *************** *** 1339,1346 **** int i, j, index, len, nwritten, islist; assert(seq != NULL); - if (f->f_fp == NULL) - return err_closed(); result = NULL; list = NULL; --- 1416,1421 ---- *************** *** 1417,1423 **** /* Since we are releasing the global lock, the following code may *not* execute Python code. */ ! Py_BEGIN_ALLOW_THREADS f->f_softspace = 0; errno = 0; for (i = 0; i < j; i++) { --- 1492,1503 ---- /* Since we are releasing the global lock, the following code may *not* execute Python code. */ ! ACQUIRE_FILE_LOCK(f) ! if (f->f_fp) { ! RELEASE_FILE_LOCK_SUB(f) ! err_closed(); ! goto error; ! } f->f_softspace = 0; errno = 0; for (i = 0; i < j; i++) { *************** *** 1426,1438 **** nwritten = fwrite(PyString_AS_STRING(line), 1, len, f->f_fp); if (nwritten != len) { - Py_BLOCK_THREADS - PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); goto error; } } ! Py_END_ALLOW_THREADS if (j < CHUNKSIZE) break; --- 1506,1518 ---- nwritten = fwrite(PyString_AS_STRING(line), 1, len, f->f_fp); if (nwritten != len) { clearerr(f->f_fp); + RELEASE_FILE_LOCK_SUB(f) + PyErr_SetFromErrno(PyExc_IOError); goto error; } } ! RELEASE_FILE_LOCK(f) if (j < CHUNKSIZE) break; *************** *** 1450,1457 **** static PyObject * file_getiter(PyFileObject *f) { ! if (f->f_fp == NULL) return err_closed(); Py_INCREF(f); return (PyObject *)f; } --- 1530,1544 ---- static PyObject * file_getiter(PyFileObject *f) { ! Py_BEGIN_ALLOW_THREADS ! PyFile_LOCK(f); ! if (f->f_fp == NULL) { ! PyFile_UNLOCK(f); ! Py_BLOCK_THREADS return err_closed(); + } + PyFile_UNLOCK(f); + Py_END_ALLOW_THREADS Py_INCREF(f); return (PyObject *)f; } *************** *** 1572,1578 **** static PyObject * get_closed(PyFileObject *f, void *closure) { ! return PyBool_FromLong((long)(f->f_fp == 0)); } #ifdef WITH_UNIVERSAL_NEWLINES static PyObject * --- 1659,1671 ---- static PyObject * get_closed(PyFileObject *f, void *closure) { ! int closed; ! Py_BEGIN_ALLOW_THREADS ! PyFile_LOCK(f); ! closed = f->f_fp ? 0 : 1; ! PyFile_UNLOCK(f); ! Py_END_ALLOW_THREADS ! return PyBool_FromLong((long) closed); } #ifdef WITH_UNIVERSAL_NEWLINES static PyObject * *************** *** 1630,1635 **** --- 1723,1729 ---- readahead(PyFileObject *f, int bufsize) { int chunksize; + int err = 0; if (f->f_buf != NULL) { if( (f->f_bufend - f->f_bufptr) >= 1) *************** *** 1641,1658 **** return -1; } Py_BEGIN_ALLOW_THREADS errno = 0; chunksize = Py_UniversalNewlineFread( ! f->f_buf, bufsize, f->f_fp, (PyObject *)f); ! Py_END_ALLOW_THREADS if (chunksize == 0) { if (ferror(f->f_fp)) { ! PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); - drop_readahead(f); - return -1; } } f->f_bufptr = f->f_buf; f->f_bufend = f->f_buf + chunksize; return 0; --- 1735,1763 ---- return -1; } Py_BEGIN_ALLOW_THREADS + PyFile_LOCK(f); + if (f->f_fp == NULL) { + PyFile_UNLOCK(f); + Py_BLOCK_THREADS + err_closed(); + return -1; + } errno = 0; chunksize = Py_UniversalNewlineFread( ! f->f_buf, bufsize, (PyObject *)f); if (chunksize == 0) { if (ferror(f->f_fp)) { ! err = 1; clearerr(f->f_fp); } } + PyFile_UNLOCK(f); + Py_END_ALLOW_THREADS + if (chunksize == 0 && err) { + PyErr_SetFromErrno(PyExc_IOError); + drop_readahead(f); + return -1; + } f->f_bufptr = f->f_buf; f->f_bufend = f->f_buf + chunksize; return 0; *************** *** 1715,1727 **** { PyStringObject* l; - int i; - - if (f->f_fp == NULL) - return err_closed(); - - i = f->f_softspace; - l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE); if (l == NULL || PyString_GET_SIZE(l) == 0) { Py_XDECREF(l); --- 1820,1825 ---- *************** *** 1747,1758 **** self = type->tp_alloc(type, 0); if (self != NULL) { /* Always fill in the name and mode, so that nobody else needs to special-case NULLs there. */ Py_INCREF(not_yet_string); ! ((PyFileObject *)self)->f_name = not_yet_string; Py_INCREF(not_yet_string); ! ((PyFileObject *)self)->f_mode = not_yet_string; } return self; } --- 1845,1858 ---- self = type->tp_alloc(type, 0); if (self != NULL) { + PyFileObject *f = (PyFileObject *)self; + f->f_lock = PyThread_allocate_lock(); /* Always fill in the name and mode, so that nobody else needs to special-case NULLs there. */ Py_INCREF(not_yet_string); ! f->f_name = not_yet_string; Py_INCREF(not_yet_string); ! f->f_mode = not_yet_string; } return self; } *************** *** 2146,2165 **** ** the different types of newlines seen. */ size_t ! Py_UniversalNewlineFread(char *buf, size_t n, ! FILE *stream, PyObject *fobj) { char *dst = buf; PyFileObject *f = (PyFileObject *)fobj; int newlinetypes, skipnextlf; assert(buf != NULL); assert(stream != NULL); - if (!fobj || !PyFile_Check(fobj)) { - errno = ENXIO; /* What can you do... */ - return -1; - } if (!f->f_univ_newline) return fread(buf, 1, n, stream); newlinetypes = f->f_newlinetypes; --- 2246,2262 ---- ** the different types of newlines seen. */ size_t ! Py_UniversalNewlineFread(char *buf, size_t n, PyObject *fobj) { char *dst = buf; PyFileObject *f = (PyFileObject *)fobj; int newlinetypes, skipnextlf; + FILE *stream = f->f_fp; + assert(PyFile_Check(fobj)); assert(buf != NULL); assert(stream != NULL); if (!f->f_univ_newline) return fread(buf, 1, n, stream); newlinetypes = f->f_newlinetypes;