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.
This commit is contained in:
Guido van Rossum 2000-03-13 16:27:06 +00:00
parent d724b23420
commit ee70ad1e52

View file

@ -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;
}
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;
}
} }
Py_END_ALLOW_THREADS 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);
}
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_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[] = {