From cf31d384f1d2ca09f817f154892eaa6860c10144 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Mar 2018 17:48:53 +1100 Subject: [PATCH] py/stream: Switch stream close operation from method to ioctl. This patch moves the implementation of stream closure from a dedicated method to the ioctl of the stream protocol, for each type that implements closing. The benefits of this are: 1. Rounds out the stream ioctl function, which already includes flush, seek and poll (among other things). 2. Makes calling mp_stream_close() on an object slightly more efficient because it now no longer needs to lookup the close method and call it, rather it just delegates straight to the ioctl function (if it exists). 3. Reduces code size and allows future types that implement the stream protocol to be smaller because they don't need a dedicated close method. Code size reduction is around 200 bytes smaller for x86 archs and around 30 bytes smaller for the bare-metal archs. --- extmod/modlwip.c | 72 ++++++++++++++++------------------ extmod/modussl_axtls.c | 35 ++++++++++------- extmod/modussl_mbedtls.c | 35 ++++++++++------- extmod/modwebrepl.c | 21 +++++++--- extmod/modwebsocket.c | 15 +++---- extmod/vfs_fat_file.c | 30 +++++++------- ports/cc3200/mods/modusocket.c | 15 +++---- ports/esp32/modsocket.c | 27 ++++++------- ports/stm32/modusocket.c | 22 +++++------ ports/unix/file.c | 20 ++++------ ports/unix/modusocket.c | 34 ++++++++++------ ports/zephyr/modusocket.c | 33 ++++++++++------ py/objstringio.c | 30 ++++++-------- py/stream.c | 18 +++++---- py/stream.h | 3 +- 15 files changed, 215 insertions(+), 195 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 2c194e1bd8..9810089da3 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -637,42 +637,6 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s return socket; } -STATIC mp_obj_t lwip_socket_close(mp_obj_t self_in) { - lwip_socket_obj_t *socket = self_in; - bool socket_is_listener = false; - - if (socket->pcb.tcp == NULL) { - return mp_const_none; - } - switch (socket->type) { - case MOD_NETWORK_SOCK_STREAM: { - if (socket->pcb.tcp->state == LISTEN) { - socket_is_listener = true; - } - if (tcp_close(socket->pcb.tcp) != ERR_OK) { - DEBUG_printf("lwip_close: had to call tcp_abort()\n"); - tcp_abort(socket->pcb.tcp); - } - break; - } - case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; - //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; - } - socket->pcb.tcp = NULL; - socket->state = _ERR_BADF; - if (socket->incoming.pbuf != NULL) { - if (!socket_is_listener) { - pbuf_free(socket->incoming.pbuf); - } else { - tcp_abort(socket->incoming.connection); - } - socket->incoming.pbuf = NULL; - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_close_obj, lwip_socket_close); - STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = self_in; @@ -1179,6 +1143,38 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR); } + } else if (request == MP_STREAM_CLOSE) { + bool socket_is_listener = false; + + if (socket->pcb.tcp == NULL) { + return 0; + } + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + if (socket->pcb.tcp->state == LISTEN) { + socket_is_listener = true; + } + if (tcp_close(socket->pcb.tcp) != ERR_OK) { + DEBUG_printf("lwip_close: had to call tcp_abort()\n"); + tcp_abort(socket->pcb.tcp); + } + break; + } + case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; + //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; + } + socket->pcb.tcp = NULL; + socket->state = _ERR_BADF; + if (socket->incoming.pbuf != NULL) { + if (!socket_is_listener) { + pbuf_free(socket->incoming.pbuf); + } else { + tcp_abort(socket->incoming.connection); + } + socket->incoming.pbuf = NULL; + } + ret = 0; + } else { *errcode = MP_EINVAL; ret = MP_STREAM_ERROR; @@ -1188,8 +1184,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } STATIC const mp_rom_map_elem_t lwip_socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&lwip_socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&lwip_socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&lwip_socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&lwip_socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&lwip_socket_accept_obj) }, diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 35e3106cdb..689d33305a 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -175,6 +175,25 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return r; } +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + if (self->ssl_sock != NULL) { + ssl_free(self->ssl_sock); + ssl_ctx_free(self->ssl_ctx); + self->ssl_sock = NULL; + mp_stream_close(self->sock); + } + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { // Currently supports only blocking mode (void)self_in; @@ -185,26 +204,13 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); - if (self->ssl_sock != NULL) { - ssl_free(self->ssl_sock); - ssl_ctx_free(self->ssl_ctx); - self->ssl_sock = NULL; - return mp_stream_close(self->sock); - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); - STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, #if MICROPY_PY_USSL_FINALISER { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, #endif @@ -215,6 +221,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab STATIC const mp_stream_p_t ussl_socket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; STATIC const mp_obj_type_t ussl_socket_type = { diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 197a0651c6..bd4b0c7253 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -274,20 +274,26 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + mbedtls_pk_free(&self->pkey); + mbedtls_x509_crt_free(&self->cert); + mbedtls_x509_crt_free(&self->cacert); + mbedtls_ssl_free(&self->ssl); + mbedtls_ssl_config_free(&self->conf); + mbedtls_ctr_drbg_free(&self->ctr_drbg); + mbedtls_entropy_free(&self->entropy); + mp_stream_close(self->sock); + return 0; - mbedtls_pk_free(&self->pkey); - mbedtls_x509_crt_free(&self->cert); - mbedtls_x509_crt_free(&self->cacert); - mbedtls_ssl_free(&self->ssl); - mbedtls_ssl_config_free(&self->conf); - mbedtls_ctr_drbg_free(&self->ctr_drbg); - mbedtls_entropy_free(&self->entropy); - - return mp_stream_close(self->sock); + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, @@ -295,9 +301,9 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, #if MICROPY_PY_USSL_FINALISER - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) }, }; @@ -307,6 +313,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab STATIC const mp_stream_p_t ussl_socket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; STATIC const mp_obj_type_t ussl_socket_type = { diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 42b30f5ea4..983b5a10ce 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -297,12 +297,20 @@ STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size return stream_p->write(self->sock, buf, size, errcode); } -STATIC mp_obj_t webrepl_close(mp_obj_t self_in) { - mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in); - // TODO: This is a place to do cleanup - return mp_stream_close(self->sock); +STATIC mp_uint_t webrepl_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + // TODO: This is a place to do cleanup + mp_stream_close(self->sock); + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close); STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) { size_t len; @@ -319,13 +327,14 @@ STATIC const mp_rom_map_elem_t webrepl_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&webrepl_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table); STATIC const mp_stream_p_t webrepl_stream_p = { .read = webrepl_read, .write = webrepl_write, + .ioctl = webrepl_ioctl, }; STATIC const mp_obj_type_t webrepl_type = { diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c index a651164b2f..5a826ec64c 100644 --- a/extmod/modwebsocket.c +++ b/extmod/modwebsocket.c @@ -256,6 +256,11 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); switch (request) { + case MP_STREAM_CLOSE: + // TODO: Send close signaling to the other side, otherwise it's + // abrupt close (connection abort). + mp_stream_close(self->sock); + return 0; case MP_STREAM_GET_DATA_OPTS: return self->ws_flags & FRAME_OPCODE_MASK; case MP_STREAM_SET_DATA_OPTS: { @@ -269,21 +274,13 @@ STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t } } -STATIC mp_obj_t websocket_close(mp_obj_t self_in) { - mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); - // TODO: Send close signaling to the other side, otherwise it's - // abrupt close (connection abort). - return mp_stream_close(self->sock); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(websocket_close_obj, websocket_close); - STATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&websocket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table); diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 23e5aa10ff..cbd013f160 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -103,22 +103,9 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz } -STATIC mp_obj_t file_obj_close(mp_obj_t self_in) { - pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); - // if fs==NULL then the file is closed and in that case this method is a no-op - if (self->fp.obj.fs != NULL) { - FRESULT res = f_close(&self->fp); - if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); - } - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close); - STATIC mp_obj_t file_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return file_obj_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__); @@ -153,6 +140,17 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, } return 0; + } else if (request == MP_STREAM_CLOSE) { + // if fs==NULL then the file is closed and in that case this method is a no-op + if (self->fp.obj.fs != NULL) { + FRESULT res = f_close(&self->fp); + if (res != FR_OK) { + *errcode = fresult_to_errno_table[res]; + return MP_STREAM_ERROR; + } + } + return 0; + } else { *errcode = MP_EINVAL; return MP_STREAM_ERROR; @@ -234,10 +232,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&file_obj_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&file_obj_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) }, }; diff --git a/ports/cc3200/mods/modusocket.c b/ports/cc3200/mods/modusocket.c index f587e765ae..286b1fb02b 100644 --- a/ports/cc3200/mods/modusocket.c +++ b/ports/cc3200/mods/modusocket.c @@ -336,6 +336,9 @@ STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp if (SL_FD_ISSET(sd, &xfds)) { ret |= MP_STREAM_POLL_HUP; } + } else if (request == MP_STREAM_CLOSE) { + wlan_socket_close(s); + ret = 0; } else { *_errno = MP_EINVAL; ret = MP_STREAM_ERROR; @@ -466,14 +469,6 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t return s; } -// method socket.close() -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mod_network_socket_obj_t *self = self_in; - wlan_socket_close(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); - // method socket.bind(address) STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { mod_network_socket_obj_t *self = self_in; @@ -704,8 +699,8 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 31d153964c..8b3c280635 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -83,19 +83,6 @@ void check_for_exceptions() { } } -STATIC mp_obj_t socket_close(const mp_obj_t arg0) { - socket_obj_t *self = MP_OBJ_TO_PTR(arg0); - if (self->fd >= 0) { - int ret = lwip_close_r(self->fd); - if (ret != 0) { - exception_from_errno(errno); - } - self->fd = -1; - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); - static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) { const struct addrinfo hints = { .ai_family = AF_INET, @@ -450,6 +437,16 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR; if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP; return ret; + } else if (request == MP_STREAM_CLOSE) { + if (socket->fd >= 0) { + int ret = lwip_close_r(socket->fd); + if (ret != 0) { + *errcode = errno; + return MP_STREAM_ERROR; + } + socket->fd = -1; + } + return 0; } *errcode = MP_EINVAL; @@ -457,8 +454,8 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt } STATIC const mp_map_elem_t socket_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&mp_stream_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&mp_stream_close_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj }, diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c index 71a237b0d9..0c663437e3 100644 --- a/ports/stm32/modusocket.c +++ b/ports/stm32/modusocket.c @@ -30,6 +30,7 @@ #include "py/objtuple.h" #include "py/objlist.h" #include "py/runtime.h" +#include "py/stream.h" #include "py/mperrno.h" #include "lib/netutils/netutils.h" #include "modnetwork.h" @@ -79,16 +80,6 @@ STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) { } } } -// method socket.close() -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mod_network_socket_obj_t *self = self_in; - if (self->nic != MP_OBJ_NULL) { - self->nic_type->close(self); - self->nic = MP_OBJ_NULL; - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); // method socket.bind(address) STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { @@ -347,8 +338,8 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, @@ -366,6 +357,13 @@ STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { mod_network_socket_obj_t *self = self_in; + if (request == MP_STREAM_CLOSE) { + if (self->nic != MP_OBJ_NULL) { + self->nic_type->close(self); + self->nic = MP_OBJ_NULL; + } + return 0; + } return self->nic_type->ioctl(self, request, arg, errcode); } diff --git a/ports/unix/file.c b/ports/unix/file.c index 84e9180821..9bb44c6abd 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -118,25 +118,21 @@ STATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i return MP_STREAM_ERROR; } return 0; + case MP_STREAM_CLOSE: + close(o->fd); + #ifdef MICROPY_CPYTHON_COMPAT + o->fd = -1; + #endif + return 0; default: *errcode = EINVAL; return MP_STREAM_ERROR; } } -STATIC mp_obj_t fdfile_close(mp_obj_t self_in) { - mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in); - close(self->fd); -#ifdef MICROPY_CPYTHON_COMPAT - self->fd = -1; -#endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_close_obj, fdfile_close); - STATIC mp_obj_t fdfile___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return fdfile_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___exit__); @@ -224,7 +220,7 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&fdfile_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&fdfile___exit___obj) }, }; diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index cfb6a9f5ec..ba50e6165e 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -108,19 +108,26 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return r; } -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); - // There's a POSIX drama regarding return value of close in general, - // and EINTR error in particular. See e.g. - // http://lwn.net/Articles/576478/ - // http://austingroupbugs.net/view.php?id=529 - // The rationale MicroPython follows is that close() just releases - // file descriptor. If you're interested to catch I/O errors before - // closing fd, fsync() it. - close(self->fd); - return mp_const_none; +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + // There's a POSIX drama regarding return value of close in general, + // and EINTR error in particular. See e.g. + // http://lwn.net/Articles/576478/ + // http://austingroupbugs.net/view.php?id=529 + // The rationale MicroPython follows is that close() just releases + // file descriptor. If you're interested to catch I/O errors before + // closing fd, fsync() it. + close(self->fd); + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC mp_obj_t socket_fileno(mp_obj_t self_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); @@ -359,7 +366,7 @@ STATIC const mp_rom_map_elem_t usocket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table); @@ -367,6 +374,7 @@ STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table); STATIC const mp_stream_p_t usocket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; const mp_obj_type_t mp_type_socket = { diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c index 95414a49b4..84d6fa7297 100644 --- a/ports/zephyr/modusocket.c +++ b/ports/zephyr/modusocket.c @@ -299,20 +299,31 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - socket_obj_t *socket = self_in; - if (socket->ctx != -1) { - int res = zsock_close(socket->ctx); - RAISE_SOCK_ERRNO(res); - socket->ctx = -1; +STATIC mp_uint_t sock_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + socket_obj_t *socket = o_in; + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + if (socket->ctx != -1) { + int res = zsock_close(socket->ctx); + RAISE_SOCK_ERRNO(res); + if (res == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + socket->ctx = -1; + } + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; } - return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, @@ -332,7 +343,7 @@ STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); STATIC const mp_stream_p_t socket_stream_p = { .read = sock_read, .write = sock_write, - //.ioctl = sock_ioctl, + .ioctl = sock_ioctl, }; STATIC const mp_obj_type_t socket_type = { diff --git a/py/objstringio.c b/py/objstringio.c index 5c50aa3174..b405ee21e3 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -143,6 +143,17 @@ STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, } case MP_STREAM_FLUSH: return 0; + case MP_STREAM_CLOSE: + #if MICROPY_CPYTHON_COMPAT + vstr_free(o->vstr); + o->vstr = NULL; + #else + vstr_clear(o->vstr); + o->vstr->alloc = 0; + o->vstr->len = 0; + o->pos = 0; + #endif + return 0; default: *errcode = MP_EINVAL; return MP_STREAM_ERROR; @@ -159,24 +170,9 @@ STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); -STATIC mp_obj_t stringio_close(mp_obj_t self_in) { - mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); -#if MICROPY_CPYTHON_COMPAT - vstr_free(self->vstr); - self->vstr = NULL; -#else - vstr_clear(self->vstr); - self->vstr->alloc = 0; - self->vstr->len = 0; - self->pos = 0; -#endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close); - STATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return stringio_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__); @@ -233,7 +229,7 @@ STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&stringio_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) }, diff --git a/py/stream.c b/py/stream.c index 453dee769f..f51f634b6f 100644 --- a/py/stream.c +++ b/py/stream.c @@ -105,13 +105,6 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { return stream_p; } -mp_obj_t mp_stream_close(mp_obj_t stream) { - // TODO: Still consider using ioctl for close - mp_obj_t dest[2]; - mp_load_method(stream, MP_QSTR_close, dest); - return mp_call_method_n_kw(0, 0, dest); -} - STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); @@ -434,6 +427,17 @@ mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) { return MP_OBJ_STOP_ITERATION; } +mp_obj_t mp_stream_close(mp_obj_t stream) { + const mp_stream_p_t *stream_p = mp_get_stream_raise(stream, MP_STREAM_OP_IOCTL); + int error; + mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error); + if (res == MP_STREAM_ERROR) { + mp_raise_OSError(error); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close); + STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL); diff --git a/py/stream.h b/py/stream.h index fbe3d7d859..a7d8d08f14 100644 --- a/py/stream.h +++ b/py/stream.h @@ -35,7 +35,7 @@ #define MP_STREAM_FLUSH (1) #define MP_STREAM_SEEK (2) #define MP_STREAM_POLL (3) -//#define MP_STREAM_CLOSE (4) // Not yet implemented +#define MP_STREAM_CLOSE (4) #define MP_STREAM_TIMEOUT (5) // Get/set timeout (single op) #define MP_STREAM_GET_OPTS (6) // Get stream options #define MP_STREAM_SET_OPTS (7) // Set stream options @@ -69,6 +69,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj);