diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/gc.c | 22 | ||||
-rw-r--r-- | py/mkrules.mk | 2 | ||||
-rw-r--r-- | py/modgc.c | 22 | ||||
-rw-r--r-- | py/mpconfig.h | 27 | ||||
-rw-r--r-- | py/mpstate.h | 5 | ||||
-rw-r--r-- | py/nlrthumb.c | 4 | ||||
-rw-r--r-- | py/nlrx64.S | 8 | ||||
-rw-r--r-- | py/obj.c | 8 | ||||
-rw-r--r-- | py/objstr.c | 10 | ||||
-rw-r--r-- | py/objstringio.c | 40 | ||||
-rw-r--r-- | py/objstrunicode.c | 30 | ||||
-rw-r--r-- | py/py.mk | 12 | ||||
-rw-r--r-- | py/stream.c | 91 | ||||
-rw-r--r-- | py/stream.h | 15 |
14 files changed, 266 insertions, 30 deletions
@@ -152,6 +152,12 @@ void gc_init(void *start, void *end) { // allow auto collection MP_STATE_MEM(gc_auto_collect_enabled) = 1; + #if MICROPY_GC_ALLOC_THRESHOLD + // by default, maxuint for gc threshold, effectively turning gc-by-threshold off + MP_STATE_MEM(gc_alloc_threshold) = (size_t)-1; + MP_STATE_MEM(gc_alloc_amount) = 0; + #endif + #if MICROPY_PY_THREAD mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex)); #endif @@ -294,6 +300,9 @@ STATIC void gc_sweep(void) { void gc_collect_start(void) { GC_ENTER(); MP_STATE_MEM(gc_lock_depth)++; + #if MICROPY_GC_ALLOC_THRESHOLD + MP_STATE_MEM(gc_alloc_amount) = 0; + #endif MP_STATE_MEM(gc_stack_overflow) = 0; MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); // Trace root pointers. This relies on the root pointers being organised @@ -405,6 +414,15 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser) { size_t start_block; size_t n_free = 0; int collected = !MP_STATE_MEM(gc_auto_collect_enabled); + + #if MICROPY_GC_ALLOC_THRESHOLD + if (!collected && MP_STATE_MEM(gc_alloc_amount) >= MP_STATE_MEM(gc_alloc_threshold)) { + GC_EXIT(); + gc_collect(); + GC_ENTER(); + } + #endif + for (;;) { // look for a run of n_blocks available blocks @@ -456,6 +474,10 @@ found: void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK); DEBUG_printf("gc_alloc(%p)\n", ret_ptr); + #if MICROPY_GC_ALLOC_THRESHOLD + MP_STATE_MEM(gc_alloc_amount) += n_blocks; + #endif + GC_EXIT(); // zero out the additional bytes of the newly allocated blocks diff --git a/py/mkrules.mk b/py/mkrules.mk index b77f8d600f..3cf0e30584 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -127,7 +127,7 @@ lib: $(OBJ) $(AR) rcs libmicropython.a $^ clean: - $(RM) -rf $(BUILD) + $(RM) -rf $(BUILD) $(CLEAN_EXTRA) .PHONY: clean print-cfg: diff --git a/py/modgc.c b/py/modgc.c index d68ff7e6c0..976fb89980 100644 --- a/py/modgc.c +++ b/py/modgc.c @@ -83,6 +83,25 @@ STATIC mp_obj_t gc_mem_alloc(void) { } MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc); +#if MICROPY_GC_ALLOC_THRESHOLD +STATIC mp_obj_t gc_threshold(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + if (MP_STATE_MEM(gc_alloc_threshold) == (size_t)-1) { + return MP_OBJ_NEW_SMALL_INT(-1); + } + return mp_obj_new_int(MP_STATE_MEM(gc_alloc_threshold) * MICROPY_BYTES_PER_GC_BLOCK); + } + mp_int_t val = mp_obj_get_int(args[0]); + if (val < 0) { + MP_STATE_MEM(gc_alloc_threshold) = (size_t)-1; + } else { + MP_STATE_MEM(gc_alloc_threshold) = val / MICROPY_BYTES_PER_GC_BLOCK; + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gc_threshold_obj, 0, 1, gc_threshold); +#endif + STATIC const mp_rom_map_elem_t mp_module_gc_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gc) }, { MP_ROM_QSTR(MP_QSTR_collect), MP_ROM_PTR(&gc_collect_obj) }, @@ -91,6 +110,9 @@ STATIC const mp_rom_map_elem_t mp_module_gc_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_isenabled), MP_ROM_PTR(&gc_isenabled_obj) }, { MP_ROM_QSTR(MP_QSTR_mem_free), MP_ROM_PTR(&gc_mem_free_obj) }, { MP_ROM_QSTR(MP_QSTR_mem_alloc), MP_ROM_PTR(&gc_mem_alloc_obj) }, + #if MICROPY_GC_ALLOC_THRESHOLD + { MP_ROM_QSTR(MP_QSTR_threshold), MP_ROM_PTR(&gc_threshold_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_gc_globals, mp_module_gc_globals_table); diff --git a/py/mpconfig.h b/py/mpconfig.h index aec5d40826..3808df7430 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -107,6 +107,12 @@ #define MICROPY_ALLOC_GC_STACK_SIZE (64) #endif +// Support automatic GC when reaching allocation threshold, +// configurable by gc.threshold(). +#ifndef MICROPY_GC_ALLOC_THRESHOLD +#define MICROPY_GC_ALLOC_THRESHOLD (1) +#endif + // Number of bytes to allocate initially when creating new chunks to store // interned string data. Smaller numbers lead to more chunks being needed // and more wastage at the end of the chunk. Larger numbers lead to wasted @@ -516,6 +522,12 @@ typedef double mp_float_t; #define MICROPY_STREAMS_NON_BLOCK (0) #endif +// Whether to provide stream functions with POSIX-like signatures +// (useful for porting existing libraries to MicroPython). +#ifndef MICROPY_STREAMS_POSIX_API +#define MICROPY_STREAMS_POSIX_API (0) +#endif + // Whether to call __init__ when importing builtin modules for the first time #ifndef MICROPY_MODULE_BUILTIN_INIT #define MICROPY_MODULE_BUILTIN_INIT (0) @@ -584,6 +596,11 @@ typedef double mp_float_t; #define MICROPY_PY_ASYNC_AWAIT (1) #endif +// Issue a warning when comparing str and bytes objects +#ifndef MICROPY_PY_STR_BYTES_CMP_WARN +#define MICROPY_PY_STR_BYTES_CMP_WARN (0) +#endif + // Whether str object is proper unicode #ifndef MICROPY_PY_BUILTINS_STR_UNICODE #define MICROPY_PY_BUILTINS_STR_UNICODE (0) @@ -594,6 +611,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_STR_CENTER (0) #endif +// Whether str.partition()/str.rpartition() method provided +#ifndef MICROPY_PY_BUILTINS_STR_PARTITION +#define MICROPY_PY_BUILTINS_STR_PARTITION (0) +#endif + // Whether str.splitlines() method provided #ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES #define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) @@ -1051,6 +1073,11 @@ typedef double mp_float_t; #define MP_NOINLINE __attribute__((noinline)) #endif +// Modifier for functions which should be always inlined +#ifndef MP_ALWAYSINLINE +#define MP_ALWAYSINLINE __attribute__((always_inline)) +#endif + // Condition is likely to be true, to help branch prediction #ifndef MP_LIKELY #define MP_LIKELY(x) __builtin_expect((x), 1) diff --git a/py/mpstate.h b/py/mpstate.h index 281795773f..439ed66066 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -76,6 +76,11 @@ typedef struct _mp_state_mem_t { // you can still allocate/free memory and also explicitly call gc_collect. uint16_t gc_auto_collect_enabled; + #if MICROPY_GC_ALLOC_THRESHOLD + size_t gc_alloc_amount; + size_t gc_alloc_threshold; + #endif + size_t gc_last_free_atb_index; #if MICROPY_PY_GC_COLLECT_RETVAL diff --git a/py/nlrthumb.c b/py/nlrthumb.c index a61c73c036..08a71ac7d6 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -29,6 +29,8 @@ #if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +#undef nlr_push + // We only need the functions here if we are on arm/thumb, and we are not // using setjmp/longjmp. // @@ -71,7 +73,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -unsigned int nlr_push_tail(nlr_buf_t *nlr) { +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; *top = nlr; diff --git a/py/nlrx64.S b/py/nlrx64.S index ad2b66fdb2..caea35de2b 100644 --- a/py/nlrx64.S +++ b/py/nlrx64.S @@ -37,8 +37,10 @@ #if defined(__APPLE__) && defined(__MACH__) #define NLR_TOP (_mp_state_ctx + NLR_TOP_OFFSET) +#define MP_THREAD_GET_STATE _mp_thread_get_state #else #define NLR_TOP (mp_state_ctx + NLR_TOP_OFFSET) +#define MP_THREAD_GET_STATE mp_thread_get_state #endif // offset of nlr_top within mp_state_thread_t structure @@ -87,7 +89,7 @@ _nlr_push: movq %rdi, NLR_TOP(%rip) # stor new nlr_buf (to make linked list) #else movq %rdi, %rbp # since we make a call, must save rdi in rbp - callq mp_thread_get_state # get mp_state_thread ptr into rax + callq MP_THREAD_GET_STATE # get mp_state_thread ptr into rax movq NLR_TOP_TH_OFF(%rax), %rsi # get thread.nlr_top (last nlr_buf) movq %rsi, (%rbp) # store it movq %rbp, NLR_TOP_TH_OFF(%rax) # store new nlr_buf (to make linked list) @@ -117,7 +119,7 @@ _nlr_pop: movq (%rax), %rax # load prev nlr_buf movq %rax, NLR_TOP(%rip) # store prev nlr_buf (to unlink list) #else - callq mp_thread_get_state # get mp_state_thread ptr into rax + callq MP_THREAD_GET_STATE # get mp_state_thread ptr into rax movq NLR_TOP_TH_OFF(%rax), %rdi # get thread.nlr_top (last nlr_buf) movq (%rdi), %rdi # load prev nlr_buf movq %rdi, NLR_TOP_TH_OFF(%rax) # store prev nlr_buf (to unlink list) @@ -150,7 +152,7 @@ nlr_jump: movq %rax, NLR_TOP(%rip) # store prev nlr_buf (to unlink list) #else movq %rdi, %rbp # put return value in rbp - callq mp_thread_get_state # get thread ptr in rax + callq MP_THREAD_GET_STATE # get thread ptr in rax movq %rax, %rsi # put thread ptr in rsi movq %rbp, %rax # put return value to rax (for je .fail) movq NLR_TOP_TH_OFF(%rsi), %rdi # get thread.nlr_top in rdi @@ -192,10 +192,16 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { return mp_obj_str_equal(o1, o2); } else { // a string is never equal to anything else - return false; + goto str_cmp_err; } } else if (MP_OBJ_IS_STR(o2)) { // o1 is not a string (else caught above), so the objects are not equal + str_cmp_err: + #if MICROPY_PY_STR_BYTES_CMP_WARN + if (MP_OBJ_IS_TYPE(o1, &mp_type_bytes) || MP_OBJ_IS_TYPE(o2, &mp_type_bytes)) { + mp_warning("Comparison between bytes and str"); + } + #endif return false; } diff --git a/py/objstr.c b/py/objstr.c index e51c371f7b..a6ee617c03 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -1683,6 +1683,7 @@ STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { return MP_OBJ_NEW_SMALL_INT(num_occurrences); } +#if MICROPY_PY_BUILTINS_STR_PARTITION STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, mp_int_t direction) { assert(MP_OBJ_IS_STR_OR_BYTES(self_in)); mp_obj_type_t *self_type = mp_obj_get_type(self_in); @@ -1732,6 +1733,7 @@ STATIC mp_obj_t str_partition(mp_obj_t self_in, mp_obj_t arg) { STATIC mp_obj_t str_rpartition(mp_obj_t self_in, mp_obj_t arg) { return str_partitioner(self_in, arg, -1); } +#endif // Supposedly not too critical operations, so optimize for code size STATIC mp_obj_t str_caseconv(unichar (*op)(unichar), mp_obj_t self_in) { @@ -1875,8 +1877,10 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip); MP_DEFINE_CONST_FUN_OBJ_KW(str_format_obj, 1, mp_obj_str_format); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count); +#if MICROPY_PY_BUILTINS_STR_PARTITION MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition); MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition); +#endif MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower); MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper); MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace); @@ -1915,11 +1919,13 @@ STATIC const mp_rom_map_elem_t str8_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) }, { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) }, { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, + #if MICROPY_PY_BUILTINS_STR_PARTITION { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, -#if MICROPY_PY_BUILTINS_STR_CENTER + #endif + #if MICROPY_PY_BUILTINS_STR_CENTER { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, -#endif + #endif { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, diff --git a/py/objstringio.c b/py/objstringio.c index abd4e835e8..eb2e516bb3 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -75,13 +75,18 @@ STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, (void)errcode; mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); check_stringio_is_open(o); - mp_uint_t remaining = o->vstr->alloc - o->pos; - if (size > remaining) { + mp_int_t remaining = o->vstr->alloc - o->pos; + mp_uint_t org_len = o->vstr->len; + if ((mp_int_t)size > remaining) { // Take all what's already allocated... o->vstr->len = o->vstr->alloc; // ... and add more vstr_add_len(o->vstr, size - remaining); } + // If there was a seek past EOF, clear the hole + if (o->pos > org_len) { + memset(o->vstr->buf + org_len, 0, o->pos - org_len); + } memcpy(o->vstr->buf + o->pos, buf, size); o->pos += size; if (o->pos > o->vstr->len) { @@ -90,6 +95,33 @@ STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, return size; } +STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); + switch (request) { + case MP_STREAM_SEEK: { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; + mp_uint_t ref = 0; + switch (s->whence) { + case 1: // SEEK_CUR + ref = o->pos; + break; + case 2: // SEEK_END + ref = o->vstr->len; + break; + } + o->pos = ref + s->offset; + s->offset = o->pos; + return 0; + } + case MP_STREAM_FLUSH: + return 0; + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + #define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes) STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { @@ -148,6 +180,8 @@ STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_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_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_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, @@ -159,12 +193,14 @@ STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table); STATIC const mp_stream_p_t stringio_stream_p = { .read = stringio_read, .write = stringio_write, + .ioctl = stringio_ioctl, .is_text = true, }; STATIC const mp_stream_p_t bytesio_stream_p = { .read = stringio_read, .write = stringio_write, + .ioctl = stringio_ioctl, }; const mp_obj_type_t mp_type_stringio = { diff --git a/py/objstrunicode.c b/py/objstrunicode.c index c6c775d109..8444a26892 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -116,7 +116,14 @@ STATIC mp_obj_t uni_unary_op(mp_uint_t op, mp_obj_t self_in) { // be capped to the first/last character of the string, depending on is_slice. const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, mp_obj_t index, bool is_slice) { - (void)type; + // All str functions also handle bytes objects, and they call str_index_to_ptr(), + // so it must handle bytes. + if (type == &mp_type_bytes) { + // Taken from objstr.c:str_index_to_ptr() + mp_uint_t index_val = mp_get_index(type, self_len, index, is_slice); + return self_data + index_val; + } + mp_int_t i; // Copied from mp_get_index; I don't want bounds checking, just give me // the integer as-is. (I can't bounds-check without scanning the whole @@ -142,26 +149,29 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s } } ++s; - } else if (!i) { - return self_data; // Shortcut - str[0] is its base pointer } else { // Positive indexing, correspondingly, counts from the start of the string. // It's assumed that negative indexing will generally be used with small // absolute values (eg str[-1], not str[-1000000]), which means it'll be // more efficient this way. - for (s = self_data; true; ++s) { + s = self_data; + while (1) { + // First check out-of-bounds if (s >= top) { if (is_slice) { return top; } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range")); } + // Then check completion + if (i-- == 0) { + break; + } + // Then skip UTF-8 char + ++s; while (UTF8_IS_CONT(*s)) { ++s; } - if (!i--) { - return s; - } } } return s; @@ -236,11 +246,13 @@ STATIC const mp_rom_map_elem_t struni_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) }, { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) }, { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, + #if MICROPY_PY_BUILTINS_STR_PARTITION { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, -#if MICROPY_PY_BUILTINS_STR_CENTER + #endif + #if MICROPY_PY_BUILTINS_STR_CENTER { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, -#endif + #endif { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, @@ -20,8 +20,11 @@ INC += -I../lib INC += -I../lib/netutils ifeq ($(MICROPY_PY_USSL),1) -CFLAGS_MOD += -DMICROPY_PY_USSL=1 -I../lib/axtls/ssl -I../lib/axtls/crypto -I../lib/axtls/config -LDFLAGS_MOD += -L../lib/axtls/_stage -laxtls +CFLAGS_MOD += -DMICROPY_PY_USSL=1 +ifeq ($(MICROPY_SSL_AXTLS),1) +CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I../lib/axtls/ssl -I../lib/axtls/crypto -I../lib/axtls/config +LDFLAGS_MOD += -Lbuild -laxtls +endif endif #ifeq ($(MICROPY_PY_LWIP),1) @@ -66,7 +69,7 @@ endif ifeq ($(MICROPY_PY_BTREE),1) BTREE_DIR = lib/berkeley-db-1.xx -CFLAGS_MOD += -D__DBINTERFACE_PRIVATE=1 +CFLAGS_MOD += -D__DBINTERFACE_PRIVATE=1 -Dmpool_error=printf -Dabort=abort_ -Dvirt_fd_t=mp_obj_t "-DVIRT_FD_T_HEADER=<py/obj.h>" INC += -I../$(BTREE_DIR)/PORT/include SRC_MOD += extmod/modbtree.c SRC_MOD += $(addprefix $(BTREE_DIR)/,\ @@ -205,7 +208,7 @@ PY_O_BASENAME = \ ../extmod/machine_pinbase.o \ ../extmod/machine_pulse.o \ ../extmod/machine_i2c.o \ - ../extmod/modussl.o \ + ../extmod/modussl_axtls.o \ ../extmod/modurandom.o \ ../extmod/modwebsocket.o \ ../extmod/modwebrepl.o \ @@ -218,6 +221,7 @@ PY_O_BASENAME = \ ../extmod/vfs_fat_lexer.o \ ../extmod/vfs_fat_misc.o \ ../extmod/moduos_dupterm.o \ + ../lib/embed/abort_.o \ # prepend the build destination prefix to the py object files PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) diff --git a/py/stream.c b/py/stream.c index 4fcc151dca..473eb96904 100644 --- a/py/stream.c +++ b/py/stream.c @@ -267,12 +267,24 @@ void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); } -STATIC mp_obj_t stream_write_method(mp_obj_t self_in, mp_obj_t arg) { +STATIC mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; - mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE); + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + size_t max_len = (size_t)-1; + size_t off = 0; + if (n_args == 3) { + max_len = mp_obj_get_int_truncated(args[2]); + } else if (n_args == 4) { + off = mp_obj_get_int_truncated(args[2]); + max_len = mp_obj_get_int_truncated(args[3]); + if (off > bufinfo.len) { + off = bufinfo.len; + } + } + bufinfo.len -= off; + return mp_stream_write(args[0], (byte*)bufinfo.buf + off, MIN(bufinfo.len, max_len), MP_STREAM_RW_WRITE); } -MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write_obj, stream_write_method); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj, 2, 4, stream_write_method); STATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { mp_buffer_info_t bufinfo; @@ -465,6 +477,17 @@ STATIC mp_obj_t stream_tell(mp_obj_t self) { } MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell); +STATIC mp_obj_t stream_flush(mp_obj_t self) { + const mp_stream_p_t *stream_p = mp_get_stream_raise(self, MP_STREAM_OP_IOCTL); + int error; + mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error); + if (res == MP_STREAM_ERROR) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, stream_flush); + STATIC mp_obj_t stream_ioctl(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); @@ -487,3 +510,63 @@ STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { return mp_obj_new_int(res); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj, 2, 3, stream_ioctl); + +#if MICROPY_STREAMS_POSIX_API +/* + * POSIX-like functions + * + * These functions have POSIX-compatible signature (except for "void *stream" + * first argument instead of "int fd"). They are useful to port existing + * POSIX-compatible software to work with MicroPython streams. + */ + +// errno-like variable. If any of the functions below returned with error +// status, this variable will contain error no. +int mp_stream_errno; + +ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len) { + mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t out_sz = stream_p->write(stream, buf, len, &mp_stream_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len) { + mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t out_sz = stream_p->read(stream, buf, len, &mp_stream_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence) { + const mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); + const mp_stream_p_t *stream_p = o->type->protocol; + struct mp_stream_seek_t seek_s; + seek_s.offset = offset; + seek_s.whence = whence; + mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &mp_stream_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return seek_s.offset; +} + +int mp_stream_posix_fsync(mp_obj_t stream) { + mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_FLUSH, 0, &mp_stream_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return res; +} + +#endif diff --git a/py/stream.h b/py/stream.h index b0f45e2f02..33d85e823c 100644 --- a/py/stream.h +++ b/py/stream.h @@ -27,6 +27,7 @@ #define __MICROPY_INCLUDED_PY_STREAM_H__ #include "py/obj.h" +#include "py/mperrno.h" #define MP_STREAM_ERROR ((mp_uint_t)-1) @@ -57,6 +58,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_stream_write_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_write1_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_seek_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_tell_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_flush_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_ioctl_obj); // these are for mp_get_stream_raise and can be or'd together @@ -80,13 +82,20 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf, mp_uint_t size, int *errcode, #define mp_stream_write_exactly(stream, buf, size, err) mp_stream_rw(stream, (byte*)buf, size, err, MP_STREAM_RW_WRITE) #define mp_stream_read_exactly(stream, buf, size, err) mp_stream_rw(stream, buf, size, err, MP_STREAM_RW_READ) +void mp_stream_write_adaptor(void *self, const char *buf, size_t len); + +#if MICROPY_STREAMS_POSIX_API +// Functions with POSIX-compatible signatures +ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len); +ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len); +off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence); +int mp_stream_posix_fsync(mp_obj_t stream); +#endif + #if MICROPY_STREAMS_NON_BLOCK -// TODO: This is POSIX-specific (but then POSIX is the only real thing, -// and anything else just emulates it, right?) #define mp_is_nonblocking_error(errno) ((errno) == EAGAIN || (errno) == EWOULDBLOCK) #else #define mp_is_nonblocking_error(errno) (0) #endif #endif // __MICROPY_INCLUDED_PY_STREAM_H__ -void mp_stream_write_adaptor(void *self, const char *buf, size_t len); |