[Python-checkins] r68048 - in sandbox/trunk/io-c: _bufferedio.c _iomodule.h io.c
antoine.pitrou
python-checkins at python.org
Tue Dec 30 00:27:20 CET 2008
Author: antoine.pitrou
Date: Tue Dec 30 00:27:19 2008
New Revision: 68048
Log:
Many changes:
- rewrite BufferedWriter with a fixed-size buffer (*).
This breaks two tests which are based on implementation details of the
previous version. The tests should be rewritten.
- add some interned strings for method calls.
- fix testThreads for BufferedReader.
- various other things.
(*) benchmarks:
- before:
** Streaming binary output **
[ 20KB.bin] write one byte/char at a time... 0.398 MB/s
[400KB.bin] write 20 bytes/chars at a time... 7.86 MB/s
[400KB.bin] write 4096 bytes/chars at a time... 594 MB/s
[ 10MB.bin] write 1e6 bytes/chars at a time... 400 MB/s
** Binary overwrite **
[ 20KB.bin] modify one byte/char at a time... 0.417 MB/s
[400KB.bin] modify 20 bytes/chars at a time... 7.91 MB/s
[400KB.bin] modify 4096 bytes/chars at a time... 342 MB/s
[400KB.bin] modify one byte/char every two... 0.127 MB/s
[400KB.bin] modify 1000 bytes/chars every 2000... 104 MB/s
- after:
** Streaming binary output **
[ 20KB.bin] write one byte/char at a time... 0.608 MB/s
[400KB.bin] write 20 bytes/chars at a time... 11.3 MB/s
[400KB.bin] write 4096 bytes/chars at a time... 740 MB/s
[ 10MB.bin] write 1e6 bytes/chars at a time... 1580 MB/s
** Binary overwrite **
[ 20KB.bin] modify one byte/char at a time... 0.6 MB/s
[400KB.bin] modify 20 bytes/chars at a time... 10.9 MB/s
[400KB.bin] modify 4096 bytes/chars at a time... 317 MB/s
[400KB.bin] modify one byte/char every two... 0.161 MB/s
[400KB.bin] modify 1000 bytes/chars every 2000... 132 MB/s
Modified:
sandbox/trunk/io-c/_bufferedio.c
sandbox/trunk/io-c/_iomodule.h
sandbox/trunk/io-c/io.c
Modified: sandbox/trunk/io-c/_bufferedio.c
==============================================================================
--- sandbox/trunk/io-c/_bufferedio.c (original)
+++ sandbox/trunk/io-c/_bufferedio.c Tue Dec 30 00:27:19 2008
@@ -112,7 +112,12 @@
Py_ssize_t read_pos;
PyThread_type_lock read_lock;
- PyObject *write_buf;
+ /* A static buffer of size `buffer_size` */
+ unsigned char *write_buf;
+ /* Just after the last byte actually written */
+ Py_ssize_t write_pos;
+ /* Just after the last buffered byte */
+ Py_ssize_t write_end;
PyThread_type_lock write_lock;
Py_ssize_t buffer_size;
@@ -122,6 +127,25 @@
PyObject *weakreflist;
} BufferedObject;
+/* These macros protect the BufferedObject against concurrent operations. */
+
+#define ENTER_BUFFERED_READER(self) \
+ Py_BEGIN_ALLOW_THREADS \
+ PyThread_acquire_lock(self->read_lock, 1); \
+ Py_END_ALLOW_THREADS \
+
+#define LEAVE_BUFFERED_READER(self) \
+ PyThread_release_lock(self->read_lock);
+
+#define ENTER_BUFFERED_WRITER(self) \
+ Py_BEGIN_ALLOW_THREADS \
+ PyThread_acquire_lock(self->write_lock, 1); \
+ Py_END_ALLOW_THREADS \
+
+#define LEAVE_BUFFERED_WRITER(self) \
+ PyThread_release_lock(self->write_lock);
+
+
static void
BufferedObject_dealloc(BufferedObject *self)
{
@@ -129,7 +153,18 @@
PyObject_ClearWeakRefs((PyObject *)self);
Py_CLEAR(self->raw);
Py_CLEAR(self->read_buf);
- Py_CLEAR(self->write_buf);
+ if (self->write_buf) {
+ PyMem_Free(self->write_buf);
+ self->write_buf = NULL;
+ }
+ if (self->read_lock) {
+ PyThread_free_lock(self->read_lock);
+ self->read_lock = NULL;
+ }
+ if (self->write_lock) {
+ PyThread_free_lock(self->write_lock);
+ self->read_lock = NULL;
+ }
Py_CLEAR(self->dict);
}
@@ -156,7 +191,7 @@
* and a flush may be necessary to synch both views of the current
* file state.
*/
- res = PyObject_CallMethod(self->raw, "flush", NULL);
+ res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_flush, NULL);
if (res == NULL)
return NULL;
Py_DECREF(res);
@@ -180,16 +215,16 @@
static PyObject *
BufferedIOMixin_flush(BufferedObject *self, PyObject *args)
{
- return PyObject_CallMethod(self->raw, "flush", NULL);
+ return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_flush, NULL);
}
static int
BufferedIOMixin_closed(BufferedObject *self)
{
int closed;
- PyObject *res = PyObject_GetAttrString(self->raw, "closed");
+ PyObject *res = PyObject_GetAttr(self->raw, _PyIO_str_closed);
if (res == NULL)
- return 0;
+ return -1;
closed = PyObject_IsTrue(res);
Py_DECREF(res);
return closed;
@@ -209,7 +244,7 @@
if (BufferedIOMixin_closed(self))
Py_RETURN_NONE;
- res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
+ res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
if (res == NULL) {
/* If flush() fails, just give up */
if (PyErr_ExceptionMatches(PyExc_IOError))
@@ -275,7 +310,7 @@
PyDoc_STRVAR(BufferedReader_doc,
"Create a new buffered reader using the given readable raw IO object.");
-static int _BufferedReader_reset_read_buf(BufferedObject *self)
+static int _BufferedReader_reset_buf(BufferedObject *self)
{
PyObject *oldbuf = self->read_buf;
@@ -311,7 +346,7 @@
self->buffer_size = buffer_size;
self->read_buf = NULL;
- if( _BufferedReader_reset_read_buf(self) < 0)
+ if (_BufferedReader_reset_buf(self) < 0)
return -1;
self->read_lock = PyThread_allocate_lock();
@@ -338,7 +373,7 @@
return NULL;
Py_INCREF(buf);
- if (_BufferedReader_reset_read_buf(self) < 0)
+ if (_BufferedReader_reset_buf(self) < 0)
return NULL;
/* Strip the consumed bytes */
@@ -422,8 +457,10 @@
data = NULL;
- if (current_size)
+ if (current_size) {
data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
+ self->read_pos += current_size;
+ }
while (1) {
Py_ssize_t wanted;
@@ -437,10 +474,10 @@
Py_DECREF(data);
}
- if (current_size >= n)
- break;
+ if (current_size >= n)
+ break;
- wanted = n;
+ wanted = n;
if (wanted < self->buffer_size)
wanted = self->buffer_size;
@@ -455,33 +492,27 @@
if (data == Py_None || Py_SIZE(data) == 0) {
/* EOF occurred or read() would block. */
-
if (current_size == 0) {
Py_DECREF(chunks);
-
- if( _BufferedReader_reset_read_buf(self) < 0) {
+ if (_BufferedReader_reset_buf(self) < 0) {
Py_DECREF(data);
return NULL;
}
-
return data;
}
else {
- Py_DECREF(data);
+ Py_DECREF(data);
break;
}
}
-
- current_size += Py_SIZE(data);
+ current_size += Py_SIZE(data);
}
sep = PyBytes_FromStringAndSize(NULL, 0);
-
if (sep == NULL) {
Py_DECREF(chunks);
return NULL;
}
-
res =_PyBytes_Join(sep, chunks);
Py_DECREF(sep);
Py_DECREF(chunks);
@@ -526,13 +557,11 @@
return NULL;
}
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
+ ENTER_BUFFERED_READER(self)
res = _BufferedReader_read_unlocked(self, n);
- PyThread_release_lock(self->read_lock);
+ LEAVE_BUFFERED_READER(self)
return res;
}
@@ -591,13 +620,11 @@
return NULL;
}
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
+ ENTER_BUFFERED_READER(self)
res = _BufferedReader_peek_unlocked(self, n);
- PyThread_release_lock(self->read_lock);
+ LEAVE_BUFFERED_READER(self)
return res;
}
@@ -615,9 +642,7 @@
if (n <= 0)
return PyBytes_FromStringAndSize(NULL, 0);
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
+ ENTER_BUFFERED_READER(self)
res = _BufferedReader_peek_unlocked(self, 1);
if(res == NULL)
@@ -630,9 +655,8 @@
res = _BufferedReader_read_unlocked(self, n);
- end:
- PyThread_release_lock(self->read_lock);
-
+end:
+ LEAVE_BUFFERED_READER(self)
return res;
}
@@ -647,9 +671,7 @@
return NULL;
}
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
+ ENTER_BUFFERED_READER(self)
if (whence == 1) {
pos -= Py_SIZE(self->read_buf) - self->read_pos;
@@ -657,13 +679,13 @@
res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
if (res == NULL)
- return NULL;
+ goto end;
- if (_BufferedReader_reset_read_buf(self) < 0)
+ if (_BufferedReader_reset_buf(self) < 0)
Py_CLEAR(res);
- PyThread_release_lock(self->read_lock);
-
+end:
+ LEAVE_BUFFERED_READER(self)
return res;
}
@@ -776,8 +798,17 @@
);
static int
+_BufferedWriter_reset_buf(BufferedObject *self)
+{
+ self->write_pos = 0;
+ self->write_end = 0;
+ return 0;
+}
+
+static int
BufferedWriter_init(BufferedObject *self, PyObject *args, PyObject *kwds)
{
+ /* TODO: max_buffer_size is unused, remove it */
char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
Py_ssize_t max_buffer_size = -1;
@@ -799,8 +830,13 @@
self->buffer_size = buffer_size;
self->max_buffer_size = max_buffer_size;
- self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
- if (self->write_buf == NULL)
+ Py_CLEAR(self->write_buf);
+ self->write_buf = PyMem_Malloc(self->buffer_size);
+ if (self->write_buf == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ if (_BufferedWriter_reset_buf(self) < 0)
return -1;
self->write_lock = PyThread_allocate_lock();
@@ -812,78 +848,91 @@
return 0;
}
-static PyObject *
-_BufferedWriter_flush_unlocked(BufferedObject *self)
+/* Returns the address of the `written` member if a BlockingIOError was
+ raised, NULL otherwise. The error is always re-raised. */
+static Py_ssize_t *
+_Buffered_check_blocking_error(void)
{
- Py_ssize_t written = 0;
+ PyObject *t, *v, *tb;
+ PyBlockingIOErrorObject *err;
- if (BufferedIOMixin_closed(self)) {
- PyErr_SetString(PyExc_ValueError, "flush of closed file");
+ PyErr_Fetch(&t, &v, &tb);
+ if (v == NULL || !PyErr_GivenExceptionMatches(v, PyExc_BlockingIOError)) {
+ PyErr_Restore(t, v, tb);
return NULL;
}
+ err = (PyBlockingIOErrorObject *) v;
+ /* TODO: sanity check (err->written >= 0) */
+ PyErr_Restore(t, v, tb);
+ return &err->written;
+}
- while (Py_SIZE(self->write_buf) > 0) {
- PyObject *slice, *res;
- Py_ssize_t w;
- PyObject *n = PyObject_CallMethod(self->raw, "write", "O", self->write_buf);
-
- if (n == NULL) {
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
-
- if (value == NULL ||
- !PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
- PyErr_Restore(type, value, traceback);
- return NULL;
- }
-
- w = ((PyBlockingIOErrorObject *)value)->written;
-
- /* del self->write_buf[:w] */
- slice = _PySlice_FromIndices(0, w);
- if (slice == NULL)
- return NULL;
- res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
- Py_DECREF(slice);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
+static Py_ssize_t
+_BufferedWriter_raw_write(BufferedObject *self, unsigned char *start, Py_ssize_t len)
+{
+ Py_buffer buf;
+ PyObject *memobj, *res;
+ Py_ssize_t n;
+ /* NOTE: the buffer needn't be released as its object is NULL. */
+ if (PyBuffer_FillInfo(&buf, NULL, start, len, 1, PyBUF_CONTIG_RO) == -1)
+ return -1;
+ memobj = PyMemoryView_FromBuffer(&buf);
+ if (memobj == NULL)
+ return -1;
+ res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_write, memobj, NULL);
+ Py_DECREF(memobj);
+ if (res == NULL)
+ return -1;
+ n = PyNumber_AsSsize_t(res, PyExc_ValueError);
+ Py_DECREF(res);
+ /* TODO: sanity check (0 <= n <= len) */
+ return n;
+}
- written += w;
- ((PyBlockingIOErrorObject *)value)->written = written;
+static PyObject *
+_BufferedWriter_flush_unlocked(BufferedObject *self)
+{
+ Py_ssize_t written = 0, n;
+ PyObject *res = NULL;
- PyErr_Restore(type, value, traceback);
- return NULL;
+ while (self->write_pos < self->write_end) {
+ /* Export a buffer of write_buf[write_pos:write_end].
+ NOTE: the buffer needn't be released as its object is NULL. */
+ n = _BufferedWriter_raw_write(self,
+ self->write_buf + self->write_pos,
+ self->write_end - self->write_pos);
+ if (n == -1 && PyErr_Occurred()) {
+ Py_ssize_t *w = _Buffered_check_blocking_error();
+ if (w == NULL)
+ goto error;
+ *w += written;
+ self->write_pos += n;
+ written += n;
+ /* Already re-raised */
+ goto error;
}
-
- /* del self->write_buf[:w] */
- w = PyNumber_AsSsize_t(n, PyExc_ValueError);
- Py_DECREF(n);
- if (w == -1 && PyErr_Occurred())
- return NULL;
-
- slice = _PySlice_FromIndices(0, w);
- if (slice == NULL)
- return NULL;
- res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
- Py_DECREF(slice);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- written += w;
+ /* TODO: sanity check with a macro */
+ self->write_pos += n;
+ written += n;
}
+ if (_BufferedWriter_reset_buf(self) < 0)
+ goto error;
Py_RETURN_NONE;
+
+error:
+ Py_XDECREF(res);
+ return NULL;
}
static PyObject *
BufferedWriter_write(BufferedObject *self, PyObject *args)
{
- PyObject *res;
+ PyObject *res = NULL;
Py_buffer buf;
- Py_ssize_t before, written;
+ Py_ssize_t written, avail, remaining, n;
+ /* TODO: check everywhere that write_buf is allocated */
if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
return NULL;
}
@@ -894,80 +943,87 @@
return NULL;
}
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->write_lock, 1);
- Py_END_ALLOW_THREADS
-
- /* XXX we can implement some more tricks to try and avoid
- * partial writes
- */
-
- if (Py_SIZE(self->write_buf) > self->buffer_size) {
- /* We're full, so let's pre-flush the buffer*/
- res = _BufferedWriter_flush_unlocked(self);
- if (res == NULL) {
- /* We can't accept anything else. */
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
-
- if (value != NULL &&
- PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
- ((PyBlockingIOErrorObject *)value)->written = 0;
- }
-
- PyErr_Restore(type, value, traceback);
- goto fail;
- }
+ /* Fast path: the data to write can be fully buffered */
+ avail = self->buffer_size - self->write_end;
+ if (buf.len <= avail) {
+ memcpy(self->write_buf + self->write_end, buf.buf, buf.len);
+ self->write_end += buf.len;
+ written = buf.len;
+ goto end;
}
- written = buf.len;
+ ENTER_BUFFERED_WRITER(self)
- before = Py_SIZE(self->write_buf);
- if (PyByteArray_Resize(self->write_buf, before + written) < 0) {
+ /* First write the current buffer */
+ res = _BufferedWriter_flush_unlocked(self);
+ if (res == NULL) {
+ Py_ssize_t *w = _Buffered_check_blocking_error();
+ if (w == NULL)
+ goto error;
+ /* Make some place by shifting the buffer. */
+ memmove(self->write_buf, self->write_buf + self->write_pos,
+ self->write_end - self->write_pos);
+ self->write_end -= self->write_pos;
+ self->write_pos = 0;
+ avail = self->buffer_size - self->write_end;
+ if (buf.len <= avail) {
+ /* Everything can be buffered */
+ PyErr_Clear();
+ memcpy(self->write_buf + self->write_end, buf.buf, buf.len);
+ self->write_pos += buf.len;
+ written = buf.len;
+ goto end;
+ }
+ /* Buffer as much as possible. */
+ memcpy(self->write_buf + self->write_end, buf.buf, avail);
+ self->write_pos += avail;
+ /* Already re-raised */
+ *w = avail;
res = NULL;
- goto fail;
+ goto error;
}
- memcpy(PyByteArray_AS_STRING(self->write_buf) + before, buf.buf, written);
+ Py_CLEAR(res);
- if (Py_SIZE(self->write_buf) > self->buffer_size) {
- res = _BufferedWriter_flush_unlocked(self);
- if (res == NULL) {
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
-
- if (value != NULL &&
- PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
-
- Py_ssize_t overage =
- Py_SIZE(self->write_buf) - self->max_buffer_size;
-
- if (overage > 0) {
- /* We've hit max_buffer_size. We have to accept a
- * partial write and cut back our buffer.
- */
- if (PyByteArray_Resize(self->write_buf, self->max_buffer_size) < 0)
- goto fail;
- ((PyBlockingIOErrorObject *)value)->written = overage;
- }
- else
- {
- Py_CLEAR(type);
- Py_CLEAR(value);
- Py_CLEAR(traceback);
- goto end;
- }
+ /* Then write buf itself. At this point write_buf has been emptied. */
+ remaining = buf.len;
+ written = 0;
+ while (remaining > self->buffer_size) {
+ n = _BufferedWriter_raw_write(
+ self, buf.buf + written, buf.len - written);
+ if (n == -1) {
+ Py_ssize_t *w = _Buffered_check_blocking_error();
+ if (w == NULL)
+ goto error;
+ written += *w;
+ remaining -= *w;
+ if (remaining > self->buffer_size) {
+ /* Can't buffer everything, still buffer as much as possible */
+ memcpy(self->write_buf, buf.buf + written, remaining);
+ self->write_end = self->buffer_size;
+ *w += self->buffer_size;
+ /* Already re-raised */
+ goto error;
}
-
- PyErr_Restore(type, value, traceback);
- goto fail;
+ PyErr_Clear();
+ break;
}
+ written += n;
+ remaining -= n;
}
+ if (remaining > 0) {
+ memcpy(self->write_buf, buf.buf + written, remaining);
+ written += remaining;
+ }
+ self->write_pos = 0;
+ /* TODO: sanity check (remaining >= 0) */
+ self->write_end = remaining;
- end:
+end:
res = PyLong_FromSsize_t(written);
- fail:
- PyThread_release_lock(self->write_lock);
+error:
+ LEAVE_BUFFERED_WRITER(self)
+error_unlocked:
PyBuffer_Release(&buf);
return res;
}
@@ -975,16 +1031,21 @@
static PyObject *
BufferedWriter_truncate(BufferedObject *self, PyObject *args)
{
- PyObject *pos = Py_None;
+ PyObject *pos = NULL;
PyObject *res;
if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
return NULL;
}
+ /* will be parsed again by BufferedIOMixin_truncate */
+ Py_XDECREF(pos);
+
+ if (BufferedIOMixin_closed(self)) {
+ PyErr_SetString(PyExc_ValueError, "truncate of closed file");
+ return NULL;
+ }
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->write_lock, 1);
- Py_END_ALLOW_THREADS
+ ENTER_BUFFERED_WRITER(self)
res = _BufferedWriter_flush_unlocked(self);
if (res == NULL)
@@ -994,7 +1055,7 @@
res = BufferedIOMixin_truncate(self, args);
end:
- PyThread_release_lock(self->write_lock);
+ LEAVE_BUFFERED_WRITER(self)
return res;
}
@@ -1003,13 +1064,16 @@
{
PyObject *res;
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->write_lock, 1);
- Py_END_ALLOW_THREADS
+ if (BufferedIOMixin_closed(self)) {
+ PyErr_SetString(PyExc_ValueError, "flush of closed file");
+ return NULL;
+ }
+
+ ENTER_BUFFERED_WRITER(self)
res = _BufferedWriter_flush_unlocked(self);
- PyThread_release_lock(self->write_lock);
+ LEAVE_BUFFERED_WRITER(self)
return res;
}
@@ -1020,8 +1084,7 @@
PyObject *op1, *op2, *res;
op1 = PyObject_CallMethod(self->raw, "tell", NULL);
-
- op2 = PyLong_FromSsize_t(Py_SIZE(self->write_buf));
+ op2 = PyLong_FromSsize_t(self->write_end - self->write_pos);
if (op2 == NULL) {
Py_DECREF(op1);
return NULL;
@@ -1043,10 +1106,12 @@
if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
return NULL;
}
+ if (BufferedIOMixin_closed(self)) {
+ PyErr_SetString(PyExc_ValueError, "seek of closed file");
+ return NULL;
+ }
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->write_lock, 1);
- Py_END_ALLOW_THREADS
+ ENTER_BUFFERED_WRITER(self)
res = _BufferedWriter_flush_unlocked(self);
if (res == NULL)
@@ -1055,7 +1120,7 @@
res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
end:
- PyThread_release_lock(self->write_lock);
+ LEAVE_BUFFERED_WRITER(self)
return res;
}
@@ -1396,7 +1461,7 @@
self->buffer_size = buffer_size;
self->max_buffer_size = max_buffer_size;
- if( _BufferedReader_reset_read_buf(self) < 0)
+ if( _BufferedReader_reset_buf(self) < 0)
return -1;
self->read_lock = PyThread_allocate_lock();
@@ -1405,8 +1470,13 @@
return -1;
}
- self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
- if (self->write_buf == NULL)
+ Py_CLEAR(self->write_buf);
+ self->write_buf = PyMem_Malloc(self->buffer_size);
+ if (self->write_buf == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ if (_BufferedWriter_reset_buf(self) < 0)
return -1;
self->write_lock = PyThread_allocate_lock();
@@ -1421,7 +1491,7 @@
static PyObject *
BufferedRandom_tell(BufferedObject *self, PyObject *args)
{
- if (Py_SIZE(self->write_buf))
+ if (self->write_end > self->write_pos)
return BufferedWriter_tell(self, args);
else
return BufferedReader_tell(self, args);
@@ -1450,14 +1520,13 @@
if (res == NULL)
return NULL;
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
+ ENTER_BUFFERED_READER(self)
- if( _BufferedReader_reset_read_buf(self) < 0)
+ if (_BufferedReader_reset_buf(self) < 0
+ || _BufferedWriter_reset_buf(self) < 0)
Py_CLEAR(res);
- PyThread_release_lock(self->read_lock);
+ LEAVE_BUFFERED_READER(self)
return res;
}
@@ -1551,19 +1620,17 @@
PyObject *res;
/* Undo readahead */
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
-
+ ENTER_BUFFERED_READER(self)
+
res = PyObject_CallMethod(self->raw, "seek", "ni",
self->read_pos - Py_SIZE(self->read_buf), 1);
Py_XDECREF(res);
if (res != NULL) {
- if( _BufferedReader_reset_read_buf(self) < 0)
+ if (_BufferedReader_reset_buf(self) < 0)
res = NULL;
}
- PyThread_release_lock(self->read_lock);
+ LEAVE_BUFFERED_READER(self)
if (res == NULL)
return NULL;
Modified: sandbox/trunk/io-c/_iomodule.h
==============================================================================
--- sandbox/trunk/io-c/_iomodule.h (original)
+++ sandbox/trunk/io-c/_iomodule.h Tue Dec 30 00:27:19 2008
@@ -48,3 +48,9 @@
} PyBlockingIOErrorObject;
PyObject *PyExc_BlockingIOError;
+/* Implementation details */
+
+extern PyObject *_PyIO_str_closed;
+extern PyObject *_PyIO_str_flush;
+extern PyObject *_PyIO_str_read;
+extern PyObject *_PyIO_str_write;
Modified: sandbox/trunk/io-c/io.c
==============================================================================
--- sandbox/trunk/io-c/io.c (original)
+++ sandbox/trunk/io-c/io.c Tue Dec 30 00:27:19 2008
@@ -4,6 +4,13 @@
PyObject *PyIOExc_UnsupportedOperation;
+/* Various interned strings */
+
+PyObject *_PyIO_str_closed;
+PyObject *_PyIO_str_flush;
+PyObject *_PyIO_str_read;
+PyObject *_PyIO_str_write;
+
PyDoc_STRVAR(module_doc,
"The io module provides the Python interfaces to stream handling. The\n"
@@ -599,6 +606,16 @@
Py_INCREF(&PyIncrementalNewlineDecoder_Type);
PyModule_AddObject(m, "IncrementalNewlineDecoder", (PyObject *) &PyIncrementalNewlineDecoder_Type);
+ /* Interned strings */
+ if (!(_PyIO_str_closed = PyUnicode_InternFromString("closed")))
+ goto fail;
+ if (!(_PyIO_str_flush = PyUnicode_InternFromString("flush")))
+ goto fail;
+ if (!(_PyIO_str_read = PyUnicode_InternFromString("read")))
+ goto fail;
+ if (!(_PyIO_str_write = PyUnicode_InternFromString("write")))
+ goto fail;
+
return m;
fail:
More information about the Python-checkins
mailing list