Commit 5a043ecc authored by Guido van Rossum's avatar Guido van Rossum

Checking in the new, improve file.writelines() code.

This (1) avoids thread unsafety whereby another thread could zap the
list while we were using it, and (2) now supports writing arbitrary
sequences of strings.
parent e1266926
......@@ -890,40 +890,94 @@ file_writelines(f, args)
PyFileObject *f;
PyObject *args;
{
int i, n;
#define CHUNKSIZE 1000
PyObject *list, *line;
PyObject *result;
int i, j, index, len, nwritten, islist;
if (f->f_fp == NULL)
return err_closed();
if (args == NULL || !PyList_Check(args)) {
if (args == NULL || !PySequence_Check(args)) {
PyErr_SetString(PyExc_TypeError,
"writelines() requires list of strings");
"writelines() requires sequence of strings");
return NULL;
}
n = PyList_Size(args);
f->f_softspace = 0;
Py_BEGIN_ALLOW_THREADS
errno = 0;
for (i = 0; i < n; i++) {
PyObject *line = PyList_GetItem(args, i);
int len;
int nwritten;
if (!PyString_Check(line)) {
Py_BLOCK_THREADS
PyErr_SetString(PyExc_TypeError,
"writelines() requires list of strings");
islist = PyList_Check(args);
/* Strategy: slurp CHUNKSIZE lines into a private list,
checking that they are all strings, then write that list
without holding the interpreter lock, then come back for more. */
index = 0;
if (islist)
list = NULL;
else {
list = PyList_New(CHUNKSIZE);
if (list == NULL)
return NULL;
}
result = NULL;
for (;;) {
if (islist) {
Py_XDECREF(list);
list = PyList_GetSlice(args, index, index+CHUNKSIZE);
if (list == NULL)
return NULL;
j = PyList_GET_SIZE(list);
}
len = PyString_Size(line);
nwritten = fwrite(PyString_AsString(line), 1, len, f->f_fp);
if (nwritten != len) {
Py_BLOCK_THREADS
PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp);
return NULL;
else {
for (j = 0; j < CHUNKSIZE; j++) {
line = PySequence_GetItem(args, index+j);
if (line == NULL) {
if (PyErr_ExceptionMatches(
PyExc_IndexError))
{
PyErr_Clear();
break;
}
/* Some other error occurred.
XXX We may lose some output. */
goto error;
}
if (!PyString_Check(line)) {
Py_DECREF(line);
PyErr_SetString(PyExc_TypeError,
"writelines() requires sequences of strings");
goto error;
}
PyList_SetItem(list, j, line);
}
}
if (j == 0)
break;
Py_BEGIN_ALLOW_THREADS
f->f_softspace = 0;
errno = 0;
for (i = 0; i < j; i++) {
line = PyList_GET_ITEM(list, i);
len = PyString_GET_SIZE(line);
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;
index += CHUNKSIZE;
}
Py_END_ALLOW_THREADS
Py_INCREF(Py_None);
return Py_None;
result = Py_None;
error:
Py_XDECREF(list);
return result;
}
static PyMethodDef file_methods[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment