Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 252317 | Differences between
and this patch

Collapse All | Expand All

(-)file_not_specified_in_diff (-88 / +342 lines)
Line  Link Here
0
-- Include/fileobject.h
0
++ Include/fileobject.h
Lines 25-30 Link Here
25
	int f_skipnextlf;	/* Skip next \n */
25
	int f_skipnextlf;	/* Skip next \n */
26
	PyObject *f_encoding;
26
	PyObject *f_encoding;
27
	PyObject *weakreflist; /* List of weak references */
27
	PyObject *weakreflist; /* List of weak references */
28
	int unlocked_count;	/* Num. currently running sections of code
29
				   using f_fp with the GIL released. */
28
} PyFileObject;
30
} PyFileObject;
29
31
30
PyAPI_DATA(PyTypeObject) PyFile_Type;
32
PyAPI_DATA(PyTypeObject) PyFile_Type;
Lines 38-43 Link Here
38
PyAPI_FUNC(PyObject *) PyFile_FromFile(FILE *, char *, char *,
40
PyAPI_FUNC(PyObject *) PyFile_FromFile(FILE *, char *, char *,
39
                                             int (*)(FILE *));
41
                                             int (*)(FILE *));
40
PyAPI_FUNC(FILE *) PyFile_AsFile(PyObject *);
42
PyAPI_FUNC(FILE *) PyFile_AsFile(PyObject *);
43
PyAPI_FUNC(void) PyFile_IncUseCount(PyFileObject *);
44
PyAPI_FUNC(void) PyFile_DecUseCount(PyFileObject *);
41
PyAPI_FUNC(PyObject *) PyFile_Name(PyObject *);
45
PyAPI_FUNC(PyObject *) PyFile_Name(PyObject *);
42
PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int);
46
PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int);
43
PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int);
47
PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int);
44
-- Lib/test/test_file.py
48
++ Lib/test/test_file.py
Lines 1-9 Link Here
1
from __future__ import with_statement
2
1
import sys
3
import sys
2
import os
4
import os
3
import unittest
5
import unittest
6
import itertools
7
import time
8
import threading
4
from array import array
9
from array import array
5
from weakref import proxy
10
from weakref import proxy
6
11
12
from test import test_support
7
from test.test_support import TESTFN, findfile, run_unittest
13
from test.test_support import TESTFN, findfile, run_unittest
8
from UserList import UserList
14
from UserList import UserList
9
15
Lines 357-368 Link Here
357
        finally:
363
        finally:
358
            sys.stdout = save_stdout
364
            sys.stdout = save_stdout
359
365
366
class FileThreadingTests(unittest.TestCase):
367
    # These tests check the ability to call various methods of file objects
368
    # (including close()) concurrently without crashing the Python interpreter.
369
    # See #815646, #595601
370
371
    def setUp(self):
372
        self.f = None
373
        self.filename = TESTFN
374
        with open(self.filename, "w") as f:
375
            f.write("\n".join("0123456789"))
376
        self._count_lock = threading.Lock()
377
        self.close_count = 0
378
        self.close_success_count = 0
379
380
    def tearDown(self):
381
        if self.f:
382
            try:
383
                self.f.close()
384
            except (EnvironmentError, ValueError):
385
                pass
386
        try:
387
            os.remove(self.filename)
388
        except EnvironmentError:
389
            pass
390
391
    def _create_file(self):
392
        self.f = open(self.filename, "w+")
393
394
    def _close_file(self):
395
        with self._count_lock:
396
            self.close_count += 1
397
        self.f.close()
398
        with self._count_lock:
399
            self.close_success_count += 1
400
401
    def _close_and_reopen_file(self):
402
        self._close_file()
403
        # if close raises an exception thats fine, self.f remains valid so
404
        # we don't need to reopen.
405
        self._create_file()
406
407
    def _run_workers(self, func, nb_workers, duration=0.2):
408
        with self._count_lock:
409
            self.close_count = 0
410
            self.close_success_count = 0
411
        self.do_continue = True
412
        threads = []
413
        try:
414
            for i in range(nb_workers):
415
                t = threading.Thread(target=func)
416
                t.start()
417
                threads.append(t)
418
            for _ in xrange(100):
419
                time.sleep(duration/100)
420
                with self._count_lock:
421
                    if self.close_count-self.close_success_count > nb_workers+1:
422
                        if test_support.verbose:
423
                            print 'Q',
424
                        break
425
            time.sleep(duration)
426
        finally:
427
            self.do_continue = False
428
            for t in threads:
429
                t.join()
430
431
    def _test_close_open_io(self, io_func, nb_workers=5):
432
        def worker():
433
            self._create_file()
434
            funcs = itertools.cycle((
435
                lambda: io_func(),
436
                lambda: self._close_and_reopen_file(),
437
            ))
438
            for f in funcs:
439
                if not self.do_continue:
440
                    break
441
                try:
442
                    f()
443
                except (IOError, ValueError):
444
                    pass
445
        self._run_workers(worker, nb_workers)
446
        if test_support.verbose:
447
            # Useful verbose statistics when tuning this test to take
448
            # less time to run but still ensuring that its still useful.
449
            #
450
            # the percent of close calls that raised an error
451
            percent = 100. - 100.*self.close_success_count/self.close_count
452
            print self.close_count, ('%.4f ' % percent),
453
454
    def test_close_open(self):
455
        def io_func():
456
            pass
457
        self._test_close_open_io(io_func)
458
459
    def test_close_open_flush(self):
460
        def io_func():
461
            self.f.flush()
462
        self._test_close_open_io(io_func)
463
464
    def test_close_open_iter(self):
465
        def io_func():
466
            list(iter(self.f))
467
        self._test_close_open_io(io_func)
468
469
    def test_close_open_isatty(self):
470
        def io_func():
471
            self.f.isatty()
472
        self._test_close_open_io(io_func)
473
474
    def test_close_open_print(self):
475
        def io_func():
476
            print >> self.f, ''
477
        self._test_close_open_io(io_func)
478
479
    def test_close_open_read(self):
480
        def io_func():
481
            self.f.read(0)
482
        self._test_close_open_io(io_func)
483
484
    def test_close_open_readinto(self):
485
        def io_func():
486
            a = array('c', 'xxxxx')
487
            self.f.readinto(a)
488
        self._test_close_open_io(io_func)
489
490
    def test_close_open_readline(self):
491
        def io_func():
492
            self.f.readline()
493
        self._test_close_open_io(io_func)
494
495
    def test_close_open_readlines(self):
496
        def io_func():
497
            self.f.readlines()
498
        self._test_close_open_io(io_func)
499
500
    def test_close_open_seek(self):
501
        def io_func():
502
            self.f.seek(0, 0)
503
        self._test_close_open_io(io_func)
504
505
    def test_close_open_tell(self):
506
        def io_func():
507
            self.f.tell()
508
        self._test_close_open_io(io_func)
509
510
    def test_close_open_truncate(self):
511
        def io_func():
512
            self.f.truncate()
513
        self._test_close_open_io(io_func)
514
515
    def test_close_open_write(self):
516
        def io_func():
517
            self.f.write('')
518
        self._test_close_open_io(io_func)
519
520
    def test_close_open_writelines(self):
521
        def io_func():
522
            self.f.writelines('')
523
        self._test_close_open_io(io_func)
360
524
361
def test_main():
525
def test_main():
362
    # Historically, these tests have been sloppy about removing TESTFN.
526
    # Historically, these tests have been sloppy about removing TESTFN.
363
    # So get rid of it no matter what.
527
    # So get rid of it no matter what.
364
    try:
528
    try:
365
        run_unittest(AutoFileTests, OtherFileTests, StdoutTests)
529
        run_unittest(AutoFileTests, OtherFileTests, StdoutTests, FileThreadingTests)
366
    finally:
530
    finally:
367
        if os.path.exists(TESTFN):
531
        if os.path.exists(TESTFN):
368
            os.unlink(TESTFN)
532
            os.unlink(TESTFN)
369
-- Misc/NEWS
533
++ Misc/NEWS
Lines 318-323 Link Here
318
Extension Modules
318
Extension Modules
319
-----------------
319
-----------------
320
320
321
- Issue #815646: Individual file objects may now be used from multiple
322
  threads at once without fear of crashing the Python interpreter.  If
323
  file.close() is called while an object is in use by another thread
324
  an IOError exception will be raised and the file will not be closed.
325
321
- Fix deallocation of array objects when allocation ran out of memory.
326
- Fix deallocation of array objects when allocation ran out of memory.
322
  Remove array test case that was incorrect on 64-bit systems.
327
  Remove array test case that was incorrect on 64-bit systems.
323
328
324
-- Objects/fileobject.c
329
++ Objects/fileobject.c
Lines 48-53 Link Here
48
#define NEWLINE_LF 2		/* \n newline seen */
48
#define NEWLINE_LF 2		/* \n newline seen */
49
#define NEWLINE_CRLF 4		/* \r\n newline seen */
49
#define NEWLINE_CRLF 4		/* \r\n newline seen */
50
50
51
/*
52
 * These macros release the GIL while preventing the f_close() function being
53
 * called in the interval between them.  For that purpose, a running total of
54
 * the number of currently running unlocked code sections is kept in
55
 * the unlocked_count field of the PyFileObject. The close() method raises
56
 * an IOError if that field is non-zero.  See issue #815646, #595601.
57
 */
58
59
#define FILE_BEGIN_ALLOW_THREADS(fobj) \
60
{ \
61
	fobj->unlocked_count++; \
62
	Py_BEGIN_ALLOW_THREADS
63
64
#define FILE_END_ALLOW_THREADS(fobj) \
65
	Py_END_ALLOW_THREADS \
66
	fobj->unlocked_count--; \
67
	assert(fobj->unlocked_count >= 0); \
68
}
69
70
#define FILE_ABORT_ALLOW_THREADS(fobj) \
71
	Py_BLOCK_THREADS \
72
	fobj->unlocked_count--; \
73
	assert(fobj->unlocked_count >= 0);
74
51
#ifdef __cplusplus
75
#ifdef __cplusplus
52
extern "C" {
76
extern "C" {
53
#endif
77
#endif
Lines 61-66 Link Here
61
		return ((PyFileObject *)f)->f_fp;
85
		return ((PyFileObject *)f)->f_fp;
62
}
86
}
63
87
88
void PyFile_IncUseCount(PyFileObject *fobj)
89
{
90
	fobj->unlocked_count++;
91
}
92
93
void PyFile_DecUseCount(PyFileObject *fobj)
94
{
95
	fobj->unlocked_count--;
96
	assert(fobj->unlocked_count >= 0);
97
}
98
64
PyObject *
99
PyObject *
65
PyFile_Name(PyObject *f)
100
PyFile_Name(PyObject *f)
66
{
101
{
Lines 70-75 Link Here
70
		return ((PyFileObject *)f)->f_name;
105
		return ((PyFileObject *)f)->f_name;
71
}
106
}
72
107
108
/* This is a safe wrapper around PyObject_Print to print to the FILE
109
   of a PyFileObject. PyObject_Print releases the GIL but knows nothing
110
   about PyFileObject. */
111
static int
112
file_PyObject_Print(PyObject *op, PyFileObject *f, int flags)
113
{
114
	int result;
115
	PyFile_IncUseCount(f);
116
	result = PyObject_Print(op, f->f_fp, flags);
117
	PyFile_DecUseCount(f);
118
	return result;
119
}
120
73
/* On Unix, fopen will succeed for directories.
121
/* On Unix, fopen will succeed for directories.
74
   In Python, there should be no file objects referring to
122
   In Python, there should be no file objects referring to
75
   directories, so we need a check.  */
123
   directories, so we need a check.  */
Lines 224-243 Link Here
224
		PyObject *wmode;
272
		PyObject *wmode;
225
		wmode = PyUnicode_DecodeASCII(newmode, strlen(newmode), NULL);
273
		wmode = PyUnicode_DecodeASCII(newmode, strlen(newmode), NULL);
226
		if (f->f_name && wmode) {
274
		if (f->f_name && wmode) {
227
			Py_BEGIN_ALLOW_THREADS
275
			FILE_BEGIN_ALLOW_THREADS(f)
228
			/* PyUnicode_AS_UNICODE OK without thread
276
			/* PyUnicode_AS_UNICODE OK without thread
229
			   lock as it is a simple dereference. */
277
			   lock as it is a simple dereference. */
230
			f->f_fp = _wfopen(PyUnicode_AS_UNICODE(f->f_name),
278
			f->f_fp = _wfopen(PyUnicode_AS_UNICODE(f->f_name),
231
					  PyUnicode_AS_UNICODE(wmode));
279
					  PyUnicode_AS_UNICODE(wmode));
232
			Py_END_ALLOW_THREADS
280
			FILE_END_ALLOW_THREADS(f)
233
		}
281
		}
234
		Py_XDECREF(wmode);
282
		Py_XDECREF(wmode);
235
	}
283
	}
236
#endif
284
#endif
237
	if (NULL == f->f_fp && NULL != name) {
285
	if (NULL == f->f_fp && NULL != name) {
238
		Py_BEGIN_ALLOW_THREADS
286
		FILE_BEGIN_ALLOW_THREADS(f)
239
		f->f_fp = fopen(name, newmode);
287
		f->f_fp = fopen(name, newmode);
240
		Py_END_ALLOW_THREADS
288
		FILE_END_ALLOW_THREADS(f)
241
	}
289
	}
242
290
243
	if (f->f_fp == NULL) {
291
	if (f->f_fp == NULL) {
Lines 275-280 Link Here
275
	return (PyObject *)f;
323
	return (PyObject *)f;
276
}
324
}
277
325
326
static PyObject *
327
close_the_file(PyFileObject *f)
328
{
329
	int sts = 0;
330
	int (*local_close)(FILE *);
331
	FILE *local_fp = f->f_fp;
332
	if (local_fp != NULL) {
333
		local_close = f->f_close;
334
		if (local_close != NULL && f->unlocked_count > 0) {
335
			if (f->ob_refcnt > 0) {
336
				PyErr_SetString(PyExc_IOError,
337
					"close() called during concurrent "
338
					"operation on the same file object.");
339
			} else {
340
				/* This should not happen unless someone is
341
				 * carelessly playing with the PyFileObject
342
				 * struct fields and/or its associated FILE
343
				 * pointer. */
344
				PyErr_SetString(PyExc_SystemError,
345
					"PyFileObject locking error in "
346
					"destructor (refcnt <= 0 at close).");
347
			}
348
			return NULL;
349
		}
350
		/* NULL out the FILE pointer before releasing the GIL, because
351
		 * it will not be valid anymore after the close() function is
352
		 * called. */
353
		f->f_fp = NULL;
354
		if (local_close != NULL) {
355
			Py_BEGIN_ALLOW_THREADS
356
			errno = 0;
357
			sts = (*local_close)(local_fp);
358
			Py_END_ALLOW_THREADS
359
			if (sts == EOF)
360
				return PyErr_SetFromErrno(PyExc_IOError);
361
			if (sts != 0)
362
				return PyInt_FromLong((long)sts);
363
		}
364
	}
365
	Py_RETURN_NONE;
366
}
367
278
PyObject *
368
PyObject *
279
PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE *))
369
PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE *))
280
{
370
{
Lines 390-408 Link Here
390
static void
480
static void
391
file_dealloc(PyFileObject *f)
481
file_dealloc(PyFileObject *f)
392
{
482
{
393
	int sts = 0;
483
	PyObject *ret;
394
	if (f->weakreflist != NULL)
484
	if (f->weakreflist != NULL)
395
		PyObject_ClearWeakRefs((PyObject *) f);
485
		PyObject_ClearWeakRefs((PyObject *) f);
396
	if (f->f_fp != NULL && f->f_close != NULL) {
486
	ret = close_the_file(f);
397
		Py_BEGIN_ALLOW_THREADS
487
	if (!ret) {
398
		sts = (*f->f_close)(f->f_fp);
488
		PySys_WriteStderr("close failed in file object destructor:\n");
399
		Py_END_ALLOW_THREADS
489
		PyErr_Print();
400
		if (sts == EOF) 
490
	}
401
#ifdef HAVE_STRERROR
491
	else {
402
			PySys_WriteStderr("close failed: [Errno %d] %s\n", errno, strerror(errno)); 
492
		Py_DECREF(ret);
403
#else
404
			PySys_WriteStderr("close failed: [Errno %d]\n", errno); 
405
#endif
406
	}
493
	}
407
	PyMem_Free(f->f_setbuf);
494
	PyMem_Free(f->f_setbuf);
408
	Py_XDECREF(f->f_name);
495
	Py_XDECREF(f->f_name);
Lines 440-463 Link Here
440
static PyObject *
527
static PyObject *
441
file_close(PyFileObject *f)
528
file_close(PyFileObject *f)
442
{
529
{
443
	int sts = 0;
530
	PyObject *sts = close_the_file(f);
444
	if (f->f_fp != NULL) {
445
		if (f->f_close != NULL) {
446
			Py_BEGIN_ALLOW_THREADS
447
			errno = 0;
448
			sts = (*f->f_close)(f->f_fp);
449
			Py_END_ALLOW_THREADS
450
		}
451
		f->f_fp = NULL;
452
	}
453
	PyMem_Free(f->f_setbuf);
531
	PyMem_Free(f->f_setbuf);
454
	f->f_setbuf = NULL;
532
	f->f_setbuf = NULL;
455
	if (sts == EOF)
533
	return sts;
456
		return PyErr_SetFromErrno(PyExc_IOError);
457
	if (sts != 0)
458
		return PyInt_FromLong((long)sts);
459
	Py_INCREF(Py_None);
460
	return Py_None;
461
}
534
}
462
535
463
536
Lines 561-570 Link Here
561
	if (PyErr_Occurred())
634
	if (PyErr_Occurred())
562
		return NULL;
635
		return NULL;
563
636
564
	Py_BEGIN_ALLOW_THREADS
637
	FILE_BEGIN_ALLOW_THREADS(f)
565
	errno = 0;
638
	errno = 0;
566
	ret = _portable_fseek(f->f_fp, offset, whence);
639
	ret = _portable_fseek(f->f_fp, offset, whence);
567
	Py_END_ALLOW_THREADS
640
	FILE_END_ALLOW_THREADS(f)
568
641
569
	if (ret != 0) {
642
	if (ret != 0) {
570
		PyErr_SetFromErrno(PyExc_IOError);
643
		PyErr_SetFromErrno(PyExc_IOError);
Lines 598-607 Link Here
598
	 * then at least on Windows).  The easiest thing is to capture
671
	 * then at least on Windows).  The easiest thing is to capture
599
	 * current pos now and seek back to it at the end.
672
	 * current pos now and seek back to it at the end.
600
	 */
673
	 */
601
	Py_BEGIN_ALLOW_THREADS
674
	FILE_BEGIN_ALLOW_THREADS(f)
602
	errno = 0;
675
	errno = 0;
603
	initialpos = _portable_ftell(f->f_fp);
676
	initialpos = _portable_ftell(f->f_fp);
604
	Py_END_ALLOW_THREADS
677
	FILE_END_ALLOW_THREADS(f)
605
	if (initialpos == -1)
678
	if (initialpos == -1)
606
		goto onioerror;
679
		goto onioerror;
607
680
Lines 626-635 Link Here
626
	 * I/O, and a flush may be necessary to synch both platform views
699
	 * I/O, and a flush may be necessary to synch both platform views
627
	 * of the current file state.
700
	 * of the current file state.
628
	 */
701
	 */
629
	Py_BEGIN_ALLOW_THREADS
702
	FILE_BEGIN_ALLOW_THREADS(f)
630
	errno = 0;
703
	errno = 0;
631
	ret = fflush(f->f_fp);
704
	ret = fflush(f->f_fp);
632
	Py_END_ALLOW_THREADS
705
	FILE_END_ALLOW_THREADS(f)
633
	if (ret != 0)
706
	if (ret != 0)
634
		goto onioerror;
707
		goto onioerror;
635
708
Lines 640-654 Link Here
640
		HANDLE hFile;
713
		HANDLE hFile;
641
714
642
		/* Have to move current pos to desired endpoint on Windows. */
715
		/* Have to move current pos to desired endpoint on Windows. */
643
		Py_BEGIN_ALLOW_THREADS
716
		FILE_BEGIN_ALLOW_THREADS(f)
644
		errno = 0;
717
		errno = 0;
645
		ret = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0;
718
		ret = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0;
646
		Py_END_ALLOW_THREADS
719
		FILE_END_ALLOW_THREADS(f)
647
		if (ret)
720
		if (ret)
648
			goto onioerror;
721
			goto onioerror;
649
722
650
		/* Truncate.  Note that this may grow the file! */
723
		/* Truncate.  Note that this may grow the file! */
651
		Py_BEGIN_ALLOW_THREADS
724
		FILE_BEGIN_ALLOW_THREADS(f)
652
		errno = 0;
725
		errno = 0;
653
		hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp));
726
		hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp));
654
		ret = hFile == (HANDLE)-1;
727
		ret = hFile == (HANDLE)-1;
Lines 657-680 Link Here
657
			if (ret)
730
			if (ret)
658
				errno = EACCES;
731
				errno = EACCES;
659
		}
732
		}
660
		Py_END_ALLOW_THREADS
733
		FILE_END_ALLOW_THREADS(f)
661
		if (ret)
734
		if (ret)
662
			goto onioerror;
735
			goto onioerror;
663
	}
736
	}
664
#else
737
#else
665
	Py_BEGIN_ALLOW_THREADS
738
	FILE_BEGIN_ALLOW_THREADS(f)
666
	errno = 0;
739
	errno = 0;
667
	ret = ftruncate(fileno(f->f_fp), newsize);
740
	ret = ftruncate(fileno(f->f_fp), newsize);
668
	Py_END_ALLOW_THREADS
741
	FILE_END_ALLOW_THREADS(f)
669
	if (ret != 0)
742
	if (ret != 0)
670
		goto onioerror;
743
		goto onioerror;
671
#endif /* !MS_WINDOWS */
744
#endif /* !MS_WINDOWS */
672
745
673
	/* Restore original file position. */
746
	/* Restore original file position. */
674
	Py_BEGIN_ALLOW_THREADS
747
	FILE_BEGIN_ALLOW_THREADS(f)
675
	errno = 0;
748
	errno = 0;
676
	ret = _portable_fseek(f->f_fp, initialpos, SEEK_SET) != 0;
749
	ret = _portable_fseek(f->f_fp, initialpos, SEEK_SET) != 0;
677
	Py_END_ALLOW_THREADS
750
	FILE_END_ALLOW_THREADS(f)
678
	if (ret)
751
	if (ret)
679
		goto onioerror;
752
		goto onioerror;
680
753
Lines 695-704 Link Here
695
768
696
	if (f->f_fp == NULL)
769
	if (f->f_fp == NULL)
697
		return err_closed();
770
		return err_closed();
698
	Py_BEGIN_ALLOW_THREADS
771
	FILE_BEGIN_ALLOW_THREADS(f)
699
	errno = 0;
772
	errno = 0;
700
	pos = _portable_ftell(f->f_fp);
773
	pos = _portable_ftell(f->f_fp);
701
	Py_END_ALLOW_THREADS
774
	FILE_END_ALLOW_THREADS(f)
775
702
	if (pos == -1) {
776
	if (pos == -1) {
703
		PyErr_SetFromErrno(PyExc_IOError);
777
		PyErr_SetFromErrno(PyExc_IOError);
704
		clearerr(f->f_fp);
778
		clearerr(f->f_fp);
Lines 734-743 Link Here
734
808
735
	if (f->f_fp == NULL)
809
	if (f->f_fp == NULL)
736
		return err_closed();
810
		return err_closed();
737
	Py_BEGIN_ALLOW_THREADS
811
	FILE_BEGIN_ALLOW_THREADS(f)
738
	errno = 0;
812
	errno = 0;
739
	res = fflush(f->f_fp);
813
	res = fflush(f->f_fp);
740
	Py_END_ALLOW_THREADS
814
	FILE_END_ALLOW_THREADS(f)
741
	if (res != 0) {
815
	if (res != 0) {
742
		PyErr_SetFromErrno(PyExc_IOError);
816
		PyErr_SetFromErrno(PyExc_IOError);
743
		clearerr(f->f_fp);
817
		clearerr(f->f_fp);
Lines 753-761 Link Here
753
	long res;
827
	long res;
754
	if (f->f_fp == NULL)
828
	if (f->f_fp == NULL)
755
		return err_closed();
829
		return err_closed();
756
	Py_BEGIN_ALLOW_THREADS
830
	FILE_BEGIN_ALLOW_THREADS(f)
757
	res = isatty((int)fileno(f->f_fp));
831
	res = isatty((int)fileno(f->f_fp));
758
	Py_END_ALLOW_THREADS
832
	FILE_END_ALLOW_THREADS(f)
759
	return PyBool_FromLong(res);
833
	return PyBool_FromLong(res);
760
}
834
}
761
835
Lines 855-865 Link Here
855
		return NULL;
929
		return NULL;
856
	bytesread = 0;
930
	bytesread = 0;
857
	for (;;) {
931
	for (;;) {
858
		Py_BEGIN_ALLOW_THREADS
932
		FILE_BEGIN_ALLOW_THREADS(f)
859
		errno = 0;
933
		errno = 0;
860
		chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread,
934
		chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread,
861
			  buffersize - bytesread, f->f_fp, (PyObject *)f);
935
			  buffersize - bytesread, f->f_fp, (PyObject *)f);
862
		Py_END_ALLOW_THREADS
936
		FILE_END_ALLOW_THREADS(f)
863
		if (chunksize == 0) {
937
		if (chunksize == 0) {
864
			if (!ferror(f->f_fp))
938
			if (!ferror(f->f_fp))
865
				break;
939
				break;
Lines 911-921 Link Here
911
		return NULL;
985
		return NULL;
912
	ndone = 0;
986
	ndone = 0;
913
	while (ntodo > 0) {
987
	while (ntodo > 0) {
914
		Py_BEGIN_ALLOW_THREADS
988
		FILE_BEGIN_ALLOW_THREADS(f)
915
		errno = 0;
989
		errno = 0;
916
		nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp,
990
		nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp,
917
						(PyObject *)f);
991
						(PyObject *)f);
918
		Py_END_ALLOW_THREADS
992
		FILE_END_ALLOW_THREADS(f)
919
		if (nnow == 0) {
993
		if (nnow == 0) {
920
			if (!ferror(f->f_fp))
994
			if (!ferror(f->f_fp))
921
				break;
995
				break;
Lines 980-986 Link Here
980
1054
981
#ifdef USE_FGETS_IN_GETLINE
1055
#ifdef USE_FGETS_IN_GETLINE
982
static PyObject*
1056
static PyObject*
983
getline_via_fgets(FILE *fp)
1057
getline_via_fgets(PyFileObject *f, FILE *fp)
984
{
1058
{
985
/* INITBUFSIZE is the maximum line length that lets us get away with the fast
1059
/* INITBUFSIZE is the maximum line length that lets us get away with the fast
986
 * no-realloc, one-fgets()-call path.  Boosting it isn't free, because we have
1060
 * no-realloc, one-fgets()-call path.  Boosting it isn't free, because we have
Lines 1013-1025 Link Here
1013
	total_v_size = INITBUFSIZE;	/* start small and pray */
1087
	total_v_size = INITBUFSIZE;	/* start small and pray */
1014
	pvfree = buf;
1088
	pvfree = buf;
1015
	for (;;) {
1089
	for (;;) {
1016
		Py_BEGIN_ALLOW_THREADS
1090
		FILE_BEGIN_ALLOW_THREADS(f)
1017
		pvend = buf + total_v_size;
1091
		pvend = buf + total_v_size;
1018
		nfree = pvend - pvfree;
1092
		nfree = pvend - pvfree;
1019
		memset(pvfree, '\n', nfree);
1093
		memset(pvfree, '\n', nfree);
1020
		assert(nfree < INT_MAX); /* Should be atmost MAXBUFSIZE */
1094
		assert(nfree < INT_MAX); /* Should be atmost MAXBUFSIZE */
1021
		p = fgets(pvfree, (int)nfree, fp);
1095
		p = fgets(pvfree, (int)nfree, fp);
1022
		Py_END_ALLOW_THREADS
1096
		FILE_END_ALLOW_THREADS(f)
1023
1097
1024
		if (p == NULL) {
1098
		if (p == NULL) {
1025
			clearerr(fp);
1099
			clearerr(fp);
Lines 1088-1100 Link Here
1088
	 * the code above for detailed comments about the logic.
1162
	 * the code above for detailed comments about the logic.
1089
	 */
1163
	 */
1090
	for (;;) {
1164
	for (;;) {
1091
		Py_BEGIN_ALLOW_THREADS
1165
		FILE_BEGIN_ALLOW_THREADS(f)
1092
		pvend = BUF(v) + total_v_size;
1166
		pvend = BUF(v) + total_v_size;
1093
		nfree = pvend - pvfree;
1167
		nfree = pvend - pvfree;
1094
		memset(pvfree, '\n', nfree);
1168
		memset(pvfree, '\n', nfree);
1095
		assert(nfree < INT_MAX);
1169
		assert(nfree < INT_MAX);
1096
		p = fgets(pvfree, (int)nfree, fp);
1170
		p = fgets(pvfree, (int)nfree, fp);
1097
		Py_END_ALLOW_THREADS
1171
		FILE_END_ALLOW_THREADS(f)
1098
1172
1099
		if (p == NULL) {
1173
		if (p == NULL) {
1100
			clearerr(fp);
1174
			clearerr(fp);
Lines 1165-1171 Link Here
1165
1239
1166
#if defined(USE_FGETS_IN_GETLINE)
1240
#if defined(USE_FGETS_IN_GETLINE)
1167
	if (n <= 0 && !univ_newline )
1241
	if (n <= 0 && !univ_newline )
1168
		return getline_via_fgets(fp);
1242
		return getline_via_fgets(f, fp);
1169
#endif
1243
#endif
1170
	total_v_size = n > 0 ? n : 100;
1244
	total_v_size = n > 0 ? n : 100;
1171
	v = PyString_FromStringAndSize((char *)NULL, total_v_size);
1245
	v = PyString_FromStringAndSize((char *)NULL, total_v_size);
Lines 1175-1181 Link Here
1175
	end = buf + total_v_size;
1249
	end = buf + total_v_size;
1176
1250
1177
	for (;;) {
1251
	for (;;) {
1178
		Py_BEGIN_ALLOW_THREADS
1252
		FILE_BEGIN_ALLOW_THREADS(f)
1179
		FLOCKFILE(fp);
1253
		FLOCKFILE(fp);
1180
		if (univ_newline) {
1254
		if (univ_newline) {
1181
			c = 'x'; /* Shut up gcc warning */
1255
			c = 'x'; /* Shut up gcc warning */
Lines 1210-1216 Link Here
1210
			buf != end)
1284
			buf != end)
1211
			;
1285
			;
1212
		FUNLOCKFILE(fp);
1286
		FUNLOCKFILE(fp);
1213
		Py_END_ALLOW_THREADS
1287
		FILE_END_ALLOW_THREADS(f)
1214
		f->f_newlinetypes = newlinetypes;
1288
		f->f_newlinetypes = newlinetypes;
1215
		f->f_skipnextlf = skipnextlf;
1289
		f->f_skipnextlf = skipnextlf;
1216
		if (c == '\n')
1290
		if (c == '\n')
Lines 1375-1381 Link Here
1375
file_readlines(PyFileObject *f, PyObject *args)
1449
file_readlines(PyFileObject *f, PyObject *args)
1376
{
1450
{
1377
	long sizehint = 0;
1451
	long sizehint = 0;
1378
	PyObject *list;
1452
	PyObject *list = NULL;
1379
	PyObject *line;
1453
	PyObject *line;
1380
	char small_buffer[SMALLCHUNK];
1454
	char small_buffer[SMALLCHUNK];
1381
	char *buffer = small_buffer;
1455
	char *buffer = small_buffer;
Lines 1403-1413 Link Here
1403
		if (shortread)
1477
		if (shortread)
1404
			nread = 0;
1478
			nread = 0;
1405
		else {
1479
		else {
1406
			Py_BEGIN_ALLOW_THREADS
1480
			FILE_BEGIN_ALLOW_THREADS(f)
1407
			errno = 0;
1481
			errno = 0;
1408
			nread = Py_UniversalNewlineFread(buffer+nfilled,
1482
			nread = Py_UniversalNewlineFread(buffer+nfilled,
1409
				buffersize-nfilled, f->f_fp, (PyObject *)f);
1483
				buffersize-nfilled, f->f_fp, (PyObject *)f);
1410
			Py_END_ALLOW_THREADS
1484
			FILE_END_ALLOW_THREADS(f)
1411
			shortread = (nread < buffersize-nfilled);
1485
			shortread = (nread < buffersize-nfilled);
1412
		}
1486
		}
1413
		if (nread == 0) {
1487
		if (nread == 0) {
Lines 1416-1425 Link Here
1416
				break;
1490
				break;
1417
			PyErr_SetFromErrno(PyExc_IOError);
1491
			PyErr_SetFromErrno(PyExc_IOError);
1418
			clearerr(f->f_fp);
1492
			clearerr(f->f_fp);
1419
		  error:
1493
			goto error;
1420
			Py_DECREF(list);
1421
			list = NULL;
1422
			goto cleanup;
1423
		}
1494
		}
1424
		totalread += nread;
1495
		totalread += nread;
1425
		p = (char *)memchr(buffer+nfilled, '\n', nread);
1496
		p = (char *)memchr(buffer+nfilled, '\n', nread);
Lines 1493-1501 Link Here
1493
		if (err != 0)
1564
		if (err != 0)
1494
			goto error;
1565
			goto error;
1495
	}
1566
	}
1496
  cleanup:
1567
1568
cleanup:
1497
	Py_XDECREF(big_buffer);
1569
	Py_XDECREF(big_buffer);
1498
	return list;
1570
	return list;
1571
1572
error:
1573
	Py_CLEAR(list);
1574
	goto cleanup;
1499
}
1575
}
1500
1576
1501
static PyObject *
1577
static PyObject *
Lines 1508-1517 Link Here
1508
	if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n))
1584
	if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n))
1509
		return NULL;
1585
		return NULL;
1510
	f->f_softspace = 0;
1586
	f->f_softspace = 0;
1511
	Py_BEGIN_ALLOW_THREADS
1587
	FILE_BEGIN_ALLOW_THREADS(f)
1512
	errno = 0;
1588
	errno = 0;
1513
	n2 = fwrite(s, 1, n, f->f_fp);
1589
	n2 = fwrite(s, 1, n, f->f_fp);
1514
	Py_END_ALLOW_THREADS
1590
	FILE_END_ALLOW_THREADS(f)
1515
	if (n2 != n) {
1591
	if (n2 != n) {
1516
		PyErr_SetFromErrno(PyExc_IOError);
1592
		PyErr_SetFromErrno(PyExc_IOError);
1517
		clearerr(f->f_fp);
1593
		clearerr(f->f_fp);
Lines 1609-1615 Link Here
1609
1685
1610
		/* Since we are releasing the global lock, the
1686
		/* Since we are releasing the global lock, the
1611
		   following code may *not* execute Python code. */
1687
		   following code may *not* execute Python code. */
1612
		Py_BEGIN_ALLOW_THREADS
1688
		FILE_BEGIN_ALLOW_THREADS(f)
1613
		f->f_softspace = 0;
1689
		f->f_softspace = 0;
1614
		errno = 0;
1690
		errno = 0;
1615
		for (i = 0; i < j; i++) {
1691
		for (i = 0; i < j; i++) {
Lines 1618-1630 Link Here
1618
			nwritten = fwrite(PyString_AS_STRING(line),
1694
			nwritten = fwrite(PyString_AS_STRING(line),
1619
					  1, len, f->f_fp);
1695
					  1, len, f->f_fp);
1620
			if (nwritten != len) {
1696
			if (nwritten != len) {
1621
				Py_BLOCK_THREADS
1697
				FILE_ABORT_ALLOW_THREADS(f)
1622
				PyErr_SetFromErrno(PyExc_IOError);
1698
				PyErr_SetFromErrno(PyExc_IOError);
1623
				clearerr(f->f_fp);
1699
				clearerr(f->f_fp);
1624
				goto error;
1700
				goto error;
1625
			}
1701
			}
1626
		}
1702
		}
1627
		Py_END_ALLOW_THREADS
1703
		FILE_END_ALLOW_THREADS(f)
1628
1704
1629
		if (j < CHUNKSIZE)
1705
		if (j < CHUNKSIZE)
1630
			break;
1706
			break;
Lines 1857-1867 Link Here
1857
		PyErr_NoMemory();
1933
		PyErr_NoMemory();
1858
		return -1;
1934
		return -1;
1859
	}
1935
	}
1860
	Py_BEGIN_ALLOW_THREADS
1936
	FILE_BEGIN_ALLOW_THREADS(f)
1861
	errno = 0;
1937
	errno = 0;
1862
	chunksize = Py_UniversalNewlineFread(
1938
	chunksize = Py_UniversalNewlineFread(
1863
		f->f_buf, bufsize, f->f_fp, (PyObject *)f);
1939
		f->f_buf, bufsize, f->f_fp, (PyObject *)f);
1864
	Py_END_ALLOW_THREADS
1940
	FILE_END_ALLOW_THREADS(f)
1865
	if (chunksize == 0) {
1941
	if (chunksize == 0) {
1866
		if (ferror(f->f_fp)) {
1942
		if (ferror(f->f_fp)) {
1867
			PyErr_SetFromErrno(PyExc_IOError);
1943
			PyErr_SetFromErrno(PyExc_IOError);
Lines 1970-1975 Link Here
1970
		Py_INCREF(Py_None);
2046
		Py_INCREF(Py_None);
1971
		((PyFileObject *)self)->f_encoding = Py_None;
2047
		((PyFileObject *)self)->f_encoding = Py_None;
1972
		((PyFileObject *)self)->weakreflist = NULL;
2048
		((PyFileObject *)self)->weakreflist = NULL;
2049
		((PyFileObject *)self)->unlocked_count = 0;
1973
	}
2050
	}
1974
	return self;
2051
	return self;
1975
}
2052
}
Lines 2157-2168 Link Here
2157
		return -1;
2234
		return -1;
2158
	}
2235
	}
2159
	else if (PyFile_Check(f)) {
2236
	else if (PyFile_Check(f)) {
2160
		FILE *fp = PyFile_AsFile(f);
2237
		PyFileObject *fobj = (PyFileObject *) f;
2161
#ifdef Py_USING_UNICODE
2238
#ifdef Py_USING_UNICODE
2162
		PyObject *enc = ((PyFileObject*)f)->f_encoding;
2239
		PyObject *enc = fobj->f_encoding;
2163
		int result;
2240
		int result;
2164
#endif
2241
#endif
2165
		if (fp == NULL) {
2242
		if (fobj->f_fp == NULL) {
2166
			err_closed();
2243
			err_closed();
2167
			return -1;
2244
			return -1;
2168
		}
2245
		}
Lines 2177-2187 Link Here
2177
			value = v;
2254
			value = v;
2178
			Py_INCREF(value);
2255
			Py_INCREF(value);
2179
		}
2256
		}
2180
		result = PyObject_Print(value, fp, flags);
2257
		result = file_PyObject_Print(value, fobj, flags);
2181
		Py_DECREF(value);
2258
		Py_DECREF(value);
2182
		return result;
2259
		return result;
2183
#else
2260
#else
2184
		return PyObject_Print(v, fp, flags);
2261
		return file_PyObject_Print(v, fobj, flags);
2185
#endif
2262
#endif
2186
	}
2263
	}
2187
	writer = PyObject_GetAttrString(f, "write");
2264
	writer = PyObject_GetAttrString(f, "write");
Lines 2219-2224 Link Here
2219
int
2296
int
2220
PyFile_WriteString(const char *s, PyObject *f)
2297
PyFile_WriteString(const char *s, PyObject *f)
2221
{
2298
{
2299
2222
	if (f == NULL) {
2300
	if (f == NULL) {
2223
		/* Should be caused by a pre-existing error */
2301
		/* Should be caused by a pre-existing error */
2224
		if (!PyErr_Occurred())
2302
		if (!PyErr_Occurred())
Lines 2227-2238 Link Here
2227
		return -1;
2305
		return -1;
2228
	}
2306
	}
2229
	else if (PyFile_Check(f)) {
2307
	else if (PyFile_Check(f)) {
2308
		PyFileObject *fobj = (PyFileObject *) f;
2230
		FILE *fp = PyFile_AsFile(f);
2309
		FILE *fp = PyFile_AsFile(f);
2231
		if (fp == NULL) {
2310
		if (fp == NULL) {
2232
			err_closed();
2311
			err_closed();
2233
			return -1;
2312
			return -1;
2234
		}
2313
		}
2314
		FILE_BEGIN_ALLOW_THREADS(fobj)
2235
		fputs(s, fp);
2315
		fputs(s, fp);
2316
		FILE_END_ALLOW_THREADS(fobj)
2236
		return 0;
2317
		return 0;
2237
	}
2318
	}
2238
	else if (!PyErr_Occurred()) {
2319
	else if (!PyErr_Occurred()) {

Return to bug 252317