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) ...@@ -890,40 +890,94 @@ file_writelines(f, args)
PyFileObject *f; PyFileObject *f;
PyObject *args; 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) if (f->f_fp == NULL)
return err_closed(); return err_closed();
if (args == NULL || !PyList_Check(args)) { if (args == NULL || !PySequence_Check(args)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"writelines() requires list of strings"); "writelines() requires sequence of strings");
return NULL; return NULL;
} }
n = PyList_Size(args); islist = PyList_Check(args);
f->f_softspace = 0;
Py_BEGIN_ALLOW_THREADS /* Strategy: slurp CHUNKSIZE lines into a private list,
errno = 0; checking that they are all strings, then write that list
for (i = 0; i < n; i++) { without holding the interpreter lock, then come back for more. */
PyObject *line = PyList_GetItem(args, i); index = 0;
int len; if (islist)
int nwritten; list = NULL;
if (!PyString_Check(line)) { else {
Py_BLOCK_THREADS list = PyList_New(CHUNKSIZE);
PyErr_SetString(PyExc_TypeError, if (list == NULL)
"writelines() requires list of strings");
return 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); else {
nwritten = fwrite(PyString_AsString(line), 1, len, f->f_fp); for (j = 0; j < CHUNKSIZE; j++) {
if (nwritten != len) { line = PySequence_GetItem(args, index+j);
Py_BLOCK_THREADS if (line == NULL) {
PyErr_SetFromErrno(PyExc_IOError); if (PyErr_ExceptionMatches(
clearerr(f->f_fp); PyExc_IndexError))
return NULL; {
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); Py_INCREF(Py_None);
return Py_None; result = Py_None;
error:
Py_XDECREF(list);
return result;
} }
static PyMethodDef file_methods[] = { 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