stream: Add compliant handling of non-blocking read()/write().
In case of empty non-blocking read()/write(), both return None. read() cannot return 0, as that means EOF, so returns another value, and then write() just follows. This is still pretty unexpected, and typical "if not len:" check would treat this as EOF. Well, non-blocking files require special handling! This also kind of makes it depending on POSIX, but well, anything else should emulate POSIX anyway ;-).
This commit is contained in:
parent
93afa230a4
commit
a592104acd
24
py/stream.c
24
py/stream.c
|
@ -25,6 +25,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "nlr.h"
|
#include "nlr.h"
|
||||||
|
@ -38,6 +39,10 @@
|
||||||
|
|
||||||
STATIC mp_obj_t stream_readall(mp_obj_t self_in);
|
STATIC mp_obj_t stream_readall(mp_obj_t self_in);
|
||||||
|
|
||||||
|
// TODO: This is POSIX-specific (but then POSIX is the only real thing,
|
||||||
|
// and anything else just emulates it, right?)
|
||||||
|
#define is_nonblocking_error(errno) ((errno) == EAGAIN || (errno) == EWOULDBLOCK)
|
||||||
|
|
||||||
STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||||
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
|
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
|
||||||
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
|
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
|
||||||
|
@ -53,6 +58,14 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||||
int error;
|
int error;
|
||||||
machine_int_t out_sz = o->type->stream_p->read(o, buf, sz, &error);
|
machine_int_t out_sz = o->type->stream_p->read(o, buf, sz, &error);
|
||||||
if (out_sz == -1) {
|
if (out_sz == -1) {
|
||||||
|
if (is_nonblocking_error(error)) {
|
||||||
|
// https://docs.python.org/3.4/library/io.html#io.RawIOBase.read
|
||||||
|
// "If the object is in non-blocking mode and no bytes are available,
|
||||||
|
// None is returned."
|
||||||
|
// This is actually very weird, as naive truth check will treat
|
||||||
|
// this as EOF.
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||||
} else {
|
} else {
|
||||||
mp_obj_t s = mp_obj_new_str(buf, out_sz, false); // will reallocate to use exact size
|
mp_obj_t s = mp_obj_new_str(buf, out_sz, false); // will reallocate to use exact size
|
||||||
|
@ -74,11 +87,16 @@ STATIC mp_obj_t stream_write(mp_obj_t self_in, mp_obj_t arg) {
|
||||||
int error;
|
int error;
|
||||||
machine_int_t out_sz = o->type->stream_p->write(self_in, bufinfo.buf, bufinfo.len, &error);
|
machine_int_t out_sz = o->type->stream_p->write(self_in, bufinfo.buf, bufinfo.len, &error);
|
||||||
if (out_sz == -1) {
|
if (out_sz == -1) {
|
||||||
|
if (is_nonblocking_error(error)) {
|
||||||
|
// http://docs.python.org/3/library/io.html#io.RawIOBase.write
|
||||||
|
// "None is returned if the raw stream is set not to block and
|
||||||
|
// no single byte could be readily written to it."
|
||||||
|
// This is for consistency with read() behavior, still weird,
|
||||||
|
// see abobe.
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||||
} else {
|
} else {
|
||||||
// http://docs.python.org/3/library/io.html#io.RawIOBase.write
|
|
||||||
// "None is returned if the raw stream is set not to block and no single byte could be readily written to it."
|
|
||||||
// Do they mean that instead of 0 they return None?
|
|
||||||
return MP_OBJ_NEW_SMALL_INT(out_sz);
|
return MP_OBJ_NEW_SMALL_INT(out_sz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue