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;
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);
}
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)) { if (!PyString_Check(line)) {
Py_BLOCK_THREADS Py_DECREF(line);
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"writelines() requires list of strings"); "writelines() requires sequences of strings");
return NULL; goto error;
} }
len = PyString_Size(line); PyList_SetItem(list, j, line);
nwritten = fwrite(PyString_AsString(line), 1, len, f->f_fp); }
}
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) { if (nwritten != len) {
Py_BLOCK_THREADS Py_BLOCK_THREADS
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp); clearerr(f->f_fp);
return NULL; goto error;
} }
} }
Py_END_ALLOW_THREADS 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[] = {