From 8d6539536ee53730f5365ec7b9a90c850069e44d Mon Sep 17 00:00:00 2001 From: wenyongh Date: Thu, 23 May 2019 17:59:42 +0800 Subject: [PATCH 1/3] Implement memory profiler, optimize memory usage, modify code indent --- core/iwasm/lib/native/base/timer_wrapper.c | 23 +- .../native/extension/sensor/sensor_mgr_ref.c | 22 +- core/iwasm/runtime/vmcore-wasm/wasm.h | 13 ++ core/iwasm/runtime/vmcore-wasm/wasm_interp.c | 21 +- core/iwasm/runtime/vmcore-wasm/wasm_loader.c | 143 +++++++++--- core/iwasm/runtime/vmcore-wasm/wasm_loader.h | 7 +- core/iwasm/runtime/vmcore-wasm/wasm_runtime.c | 11 +- core/iwasm/runtime/vmcore-wasm/wasm_runtime.h | 8 +- core/shared-lib/include/bh_memory.h | 28 +++ core/shared-lib/include/config.h | 17 +- core/shared-lib/mem-alloc/bh_memory.c | 219 +++++++++++++++++- core/shared-lib/platform/linux/bh_thread.c | 2 +- doc/memory_usage.txt | 13 ++ samples/littlevgl/README.md | 2 +- .../src/platform/linux/iwasm_main.c | 2 +- .../src/platform/zephyr/XPT2046.c | 15 +- .../src/platform/zephyr/iwasm_main.c | 21 +- samples/littlevgl/wasm-apps/Makefile_wasm_app | 2 +- 18 files changed, 463 insertions(+), 106 deletions(-) create mode 100644 doc/memory_usage.txt diff --git a/core/iwasm/lib/native/base/timer_wrapper.c b/core/iwasm/lib/native/base/timer_wrapper.c index f2a8f23c2e..da5c8943fa 100644 --- a/core/iwasm/lib/native/base/timer_wrapper.c +++ b/core/iwasm/lib/native/base/timer_wrapper.c @@ -55,8 +55,8 @@ void * thread_modulers_timer_check(void * arg) while (1) { ms_to_expiry = -1; vm_mutex_lock(&g_timer_ctx_list_mutex); - timer_ctx_node_t* elem = (timer_ctx_node_t*) bh_list_first_elem( - &g_timer_ctx_list); + timer_ctx_node_t* elem = (timer_ctx_node_t*) + bh_list_first_elem(&g_timer_ctx_list); while (elem) { int next = check_app_timers(elem->timer_ctx); if (next != -1) { @@ -72,7 +72,7 @@ void * thread_modulers_timer_check(void * arg) ms_to_expiry = 60 * 1000; vm_mutex_lock(&g_timer_ctx_list_mutex); vm_cond_reltimedwait(&g_timer_ctx_list_cond, &g_timer_ctx_list_mutex, - ms_to_expiry); + ms_to_expiry); vm_mutex_unlock(&g_timer_ctx_list_mutex); } } @@ -94,20 +94,21 @@ void init_wasm_timer() vm_recursive_mutex_init(&g_timer_ctx_list_mutex); vm_thread_create(&tm_tid, thread_modulers_timer_check, - NULL, - BH_APPLET_PRESERVED_STACK_SIZE); + NULL, BH_APPLET_PRESERVED_STACK_SIZE); } timer_ctx_t create_wasm_timer_ctx(unsigned int module_id, int prealloc_num) { timer_ctx_t ctx = create_timer_ctx(wasm_timer_callback, - wakeup_modules_timer_thread, prealloc_num, module_id); + wakeup_modules_timer_thread, + prealloc_num, + module_id); if (ctx == NULL) return NULL; - timer_ctx_node_t * node = (timer_ctx_node_t*) bh_malloc( - sizeof(timer_ctx_node_t)); + timer_ctx_node_t * node = (timer_ctx_node_t*) + bh_malloc(sizeof(timer_ctx_node_t)); if (node == NULL) { destroy_timer_ctx(ctx); return NULL; @@ -125,8 +126,8 @@ timer_ctx_t create_wasm_timer_ctx(unsigned int module_id, int prealloc_num) void destory_module_timer_ctx(unsigned int module_id) { vm_mutex_lock(&g_timer_ctx_list_mutex); - timer_ctx_node_t* elem = (timer_ctx_node_t*) bh_list_first_elem( - &g_timer_ctx_list); + timer_ctx_node_t* elem = (timer_ctx_node_t*) + bh_list_first_elem(&g_timer_ctx_list); while (elem) { if (timer_ctx_get_owner(elem->timer_ctx) == module_id) { bh_list_remove(&g_timer_ctx_list, elem); @@ -151,7 +152,7 @@ timer_ctx_t get_wasm_timer_ctx() timer_id_t wasm_create_timer(int interval, bool is_period, bool auto_start) { return sys_create_timer(get_wasm_timer_ctx(), interval, is_period, - auto_start); + auto_start); } void wasm_timer_destory(timer_id_t timer_id) diff --git a/core/iwasm/lib/native/extension/sensor/sensor_mgr_ref.c b/core/iwasm/lib/native/extension/sensor/sensor_mgr_ref.c index b2cd53d316..a509313528 100644 --- a/core/iwasm/lib/native/extension/sensor/sensor_mgr_ref.c +++ b/core/iwasm/lib/native/extension/sensor/sensor_mgr_ref.c @@ -40,13 +40,13 @@ void app_mgr_sensor_event_callback(module_data *m_data, bh_message_t msg) wasm_data *wasm_app_data = (wasm_data*) m_data->internal_data; wasm_module_inst_t inst = wasm_app_data->wasm_module_inst; - sensor_event_data_t *payload = (sensor_event_data_t*) bh_message_payload( - msg); + sensor_event_data_t *payload = (sensor_event_data_t*) + bh_message_payload(msg); if (payload == NULL) return; func_onSensorEvent = wasm_runtime_lookup_function(inst, "_on_sensor_event", - "(i32i32i32)"); + "(i32i32i32)"); if (!func_onSensorEvent) { printf("Cannot find function onRequest\n"); } else { @@ -54,18 +54,17 @@ void app_mgr_sensor_event_callback(module_data *m_data, bh_message_t msg) uint32 sensor_data_len; if (payload->data_fmt == FMT_ATTR_CONTAINER) { - sensor_data_len = attr_container_get_serialize_length( - payload->data); + sensor_data_len = attr_container_get_serialize_length(payload->data); } else { printf("Unsupported sensor data format: %d\n", payload->data_fmt); return; } sensor_data_offset = wasm_runtime_module_dup_data(inst, payload->data, - sensor_data_len); + sensor_data_len); if (sensor_data_offset == 0) { printf("Got exception running wasm code: %s\n", - wasm_runtime_get_exception(inst)); + wasm_runtime_get_exception(inst)); wasm_runtime_clear_exception(inst); return; } @@ -76,7 +75,7 @@ void app_mgr_sensor_event_callback(module_data *m_data, bh_message_t msg) if (!wasm_runtime_call_wasm(inst, NULL, func_onSensorEvent, 3, argv)) { printf(":Got exception running wasm code: %s\n", - wasm_runtime_get_exception(inst)); + wasm_runtime_get_exception(inst)); wasm_runtime_clear_exception(inst); wasm_runtime_module_free(inst, sensor_data_offset); return; @@ -130,17 +129,16 @@ void init_sensor_framework() // add the sys sensor objects add_sys_sensor("sensor_test", "This is a sensor for test", 0, 1000, - read_test_sensor, config_test_sensor); + read_test_sensor, config_test_sensor); set_sensor_reshceduler(cb_wakeup_thread); wasm_register_msg_callback(SENSOR_EVENT_WASM, - app_mgr_sensor_event_callback); + app_mgr_sensor_event_callback); wasm_register_cleanup_callback(sensor_cleanup_callback); vm_thread_create(&tid, (void *)thread_sensor_check, NULL, - BH_APPLET_PRESERVED_STACK_SIZE); - + BH_APPLET_PRESERVED_STACK_SIZE); } diff --git a/core/iwasm/runtime/vmcore-wasm/wasm.h b/core/iwasm/runtime/vmcore-wasm/wasm.h index 6917183b13..e493da9901 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm.h +++ b/core/iwasm/runtime/vmcore-wasm/wasm.h @@ -219,6 +219,15 @@ typedef struct WASMDataSeg { uint8 *data; } WASMDataSeg; +typedef struct BlockAddr { + const uint8 *start_addr; + uint8 *else_addr; + uint8 *end_addr; +} BlockAddr; + +#define BLOCK_ADDR_CACHE_SIZE 64 +#define BLOCK_ADDR_CONFLICT_SIZE 4 + typedef struct WASMModule { uint32 type_count; uint32 import_count; @@ -252,7 +261,11 @@ typedef struct WASMModule { uint32 start_function; HashMap *const_str_set; +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 HashMap *branch_set; +#else + BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE]; +#endif } WASMModule; typedef struct WASMBranchBlock { diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_interp.c b/core/iwasm/runtime/vmcore-wasm/wasm_interp.c index f883587e89..ab715a477e 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_interp.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_interp.c @@ -760,11 +760,12 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP (WASM_OP_BLOCK): read_leb_uint32(frame_ip, frame_ip_end, block_ret_type); - if (!wasm_loader_find_block_addr(module->branch_set, frame_ip, - frame_ip_end, BLOCK_TYPE_BLOCK, + if (!wasm_loader_find_block_addr(module->module, + frame_ip, frame_ip_end, + BLOCK_TYPE_BLOCK, &else_addr, &end_addr, NULL, 0)) { - wasm_runtime_set_exception(module, "wasm loader find block addr failed"); + wasm_runtime_set_exception(module, "find block addr failed"); goto got_exception; } @@ -774,11 +775,12 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP (WASM_OP_LOOP): read_leb_uint32(frame_ip, frame_ip_end, block_ret_type); - if (!wasm_loader_find_block_addr(module->branch_set, frame_ip, - frame_ip_end, BLOCK_TYPE_LOOP, + if (!wasm_loader_find_block_addr(module->module, + frame_ip, frame_ip_end, + BLOCK_TYPE_LOOP, &else_addr, &end_addr, NULL, 0)) { - wasm_runtime_set_exception(module, "wasm loader find block addr failed"); + wasm_runtime_set_exception(module, "find block addr failed"); goto got_exception; } @@ -788,11 +790,12 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP (WASM_OP_IF): read_leb_uint32(frame_ip, frame_ip_end, block_ret_type); - if (!wasm_loader_find_block_addr(module->branch_set, frame_ip, - frame_ip_end, BLOCK_TYPE_IF, + if (!wasm_loader_find_block_addr(module->module, + frame_ip, frame_ip_end, + BLOCK_TYPE_IF, &else_addr, &end_addr, NULL, 0)) { - wasm_runtime_set_exception(module, "wasm loader find block addr failed"); + wasm_runtime_set_exception(module, "find block addr failed"); goto got_exception; } diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_loader.c b/core/iwasm/runtime/vmcore-wasm/wasm_loader.c index c37a12dfef..1af9278e1e 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_loader.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_loader.c @@ -1180,10 +1180,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, return true; } +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 static uint32 branch_set_hash(const void *key) { - return ((uintptr_t)key >> 4) ^ ((uintptr_t)key >> 14); + return ((uintptr_t)key) ^ ((uintptr_t)key >> 16); } static bool @@ -1197,6 +1198,16 @@ branch_set_value_destroy(void *value) { wasm_free(value); } +#endif + +#if BEIHAI_ENABLE_MEMORY_PROFILING != 0 +static void wasm_loader_free(void *ptr) +{ + wasm_free(ptr); +} +#else +#define wasm_loader_free wasm_free +#endif static WASMModule* create_module(char *error_buf, uint32 error_buf_size) @@ -1218,15 +1229,17 @@ create_module(char *error_buf, uint32 error_buf_size) (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, NULL, - wasm_free))) + wasm_loader_free))) goto fail; +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 if (!(module->branch_set = wasm_hash_map_create(64, true, branch_set_hash, branch_set_key_equal, NULL, branch_set_value_destroy))) goto fail; +#endif return module; @@ -1361,15 +1374,17 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, NULL, - wasm_free))) + wasm_loader_free))) goto fail; +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 if (!(module->branch_set = wasm_hash_map_create(64, true, branch_set_hash, branch_set_key_equal, NULL, branch_set_value_destroy))) goto fail; +#endif if (!load(buf, size, module, error_buf, error_buf_size)) goto fail; @@ -1440,20 +1455,24 @@ wasm_loader_unload(WASMModule *module) if (module->const_str_set) wasm_hash_map_destroy(module->const_str_set); +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 if (module->branch_set) wasm_hash_map_destroy(module->branch_set); +#endif wasm_free(module); } +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 typedef struct block_addr { uint8 block_type; - uint8 *else_addr; uint8 *end_addr; + uint8 *else_addr; } block_addr; +#endif bool -wasm_loader_find_block_addr(HashMap *branch_set, +wasm_loader_find_block_addr(WASMModule *module, const uint8 *start_addr, const uint8 *code_end_addr, uint8 block_type, @@ -1466,8 +1485,10 @@ wasm_loader_find_block_addr(HashMap *branch_set, uint8 *else_addr = NULL; uint32 block_nested_depth = 1, count, i, u32, u64; uint8 opcode, u8; - block_addr *block; +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 + HashMap *branch_set = module->branch_set; + block_addr *block; if ((block = wasm_hash_map_find(branch_set, (void*)start_addr))) { if (block->block_type != block_type) return false; @@ -1476,6 +1497,25 @@ wasm_loader_find_block_addr(HashMap *branch_set, *p_end_addr = block->end_addr; return true; } +#else + BlockAddr block_stack[16] = { 0 }, *block; + uint32 j, t; + + i = ((uintptr_t)start_addr) ^ ((uintptr_t)start_addr >> 16); + i = i % BLOCK_ADDR_CACHE_SIZE; + block = module->block_addr_cache[i]; + for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) { + if (block[j].start_addr == start_addr) { + /* Cache hit */ + *p_else_addr = block[j].else_addr; + *p_end_addr = block[j].end_addr; + return true; + } + } + + /* Cache unhit */ + block_stack[0].start_addr = start_addr; +#endif while (p < code_end_addr) { opcode = *p++; @@ -1489,12 +1529,22 @@ wasm_loader_find_block_addr(HashMap *branch_set, case WASM_OP_LOOP: case WASM_OP_IF: read_leb_uint32(p, p_end, u32); /* blocktype */ +#if WASM_ENABLE_HASH_BLOCK_ADDR == 0 + if (block_nested_depth < sizeof(block_stack)/sizeof(BlockAddr)) { + block_stack[block_nested_depth].start_addr = p; + block_stack[block_nested_depth].else_addr = NULL; + } +#endif block_nested_depth++; break; case WASM_OP_ELSE: if (block_type == BLOCK_TYPE_IF && block_nested_depth == 1) else_addr = (uint8*)(p - 1); +#if WASM_ENABLE_HASH_BLOCK_ADDR == 0 + if (block_nested_depth - 1 < sizeof(block_stack)/sizeof(BlockAddr)) + block_stack[block_nested_depth - 1].else_addr = (uint8*)(p - 1); +#endif break; case WASM_OP_END: @@ -1503,7 +1553,13 @@ wasm_loader_find_block_addr(HashMap *branch_set, *p_else_addr = else_addr; *p_end_addr = (uint8*)(p - 1); - if ((block = wasm_malloc(sizeof(block_addr)))) { +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 + if (block_type == BLOCK_TYPE_IF) + block = wasm_malloc(sizeof(block_addr)); + else + block = wasm_malloc(offsetof(block_addr, else_addr)); + + if (block) { block->block_type = block_type; if (block_type == BLOCK_TYPE_IF) block->else_addr = else_addr; @@ -1512,11 +1568,41 @@ wasm_loader_find_block_addr(HashMap *branch_set, if (!wasm_hash_map_insert(branch_set, (void*)start_addr, block)) wasm_free(block); } - +#else + block_stack[0].end_addr = (uint8*)(p - 1); + for (t = 0; t < sizeof(block_stack)/sizeof(BlockAddr); t++) { + start_addr = block_stack[t].start_addr; + if (start_addr) { + i = ((uintptr_t)start_addr) ^ ((uintptr_t)start_addr >> 16); + i = i % BLOCK_ADDR_CACHE_SIZE; + block = module->block_addr_cache[i]; + for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) + if (!block[j].start_addr) + break; + + if (j == BLOCK_ADDR_CONFLICT_SIZE) { + memmove(block + 1, block, (BLOCK_ADDR_CONFLICT_SIZE - 1) * + sizeof(BlockAddr)); + j = 0; + + } + block[j].start_addr = block_stack[t].start_addr; + block[j].else_addr = block_stack[t].else_addr; + block[j].end_addr = block_stack[t].end_addr; + } + else + break; + } +#endif return true; } - else + else { block_nested_depth--; +#if WASM_ENABLE_HASH_BLOCK_ADDR == 0 + if (block_nested_depth < sizeof(block_stack)/sizeof(BlockAddr)) + block_stack[block_nested_depth].end_addr = (uint8*)(p - 1); +#endif + } break; case WASM_OP_BR: @@ -2079,14 +2165,13 @@ static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, char *error_buf, uint32 error_buf_size) { - HashMap *branch_set = module->branch_set; +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 block_addr *block; +#endif uint8 *p = func->code, *p_end = func->code + func->code_size; - uint8 *frame_lp_ref_bottom = NULL; uint8 *frame_ref_bottom = NULL, *frame_ref_boundary, *frame_ref; BranchBlock *frame_csp_bottom = NULL, *frame_csp_boundary, *frame_csp; uint32 param_count, local_count, global_count; - uint32 param_cell_num, local_cell_num; uint32 max_stack_cell_num = 0, max_csp_num = 0; uint32 stack_cell_num = 0, csp_num = 0; uint32 frame_ref_size, frame_csp_size; @@ -2107,16 +2192,6 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, local_count = func->local_count; local_types = func->local_types; - param_cell_num = wasm_get_cell_num(param_types, param_count); - local_cell_num = wasm_get_cell_num(local_types, local_count); - - if (!(frame_lp_ref_bottom = wasm_malloc(param_cell_num + local_cell_num))) { - set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: alloc memory failed"); - goto fail; - } - memset(frame_lp_ref_bottom, 0, param_cell_num + local_cell_num); - frame_ref_size = 32; if (!(frame_ref_bottom = frame_ref = wasm_malloc(frame_ref_size))) { set_error_buf(error_buf, error_buf_size, @@ -2167,7 +2242,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, (frame_csp - 1)->jumped_by_br = true; else { if (!i32_const) { - if(!wasm_loader_find_block_addr(branch_set, + if(!wasm_loader_find_block_addr(module, (frame_csp - 1)->start_addr, p_end, (frame_csp - 1)->block_type, @@ -2210,10 +2285,16 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (csp_num > 0) { frame_csp->end_addr = p - 1; - if (wasm_hash_map_find(branch_set, (void*)frame_csp->start_addr)) +#if WASM_ENABLE_HASH_BLOCK_ADDR != 0 + if (wasm_hash_map_find(module->branch_set, (void*)frame_csp->start_addr)) break; - if (!(block = wasm_malloc(sizeof(block_addr)))) { + if (frame_csp->block_type == BLOCK_TYPE_IF) + block = wasm_malloc(sizeof(block_addr)); + else + block = wasm_malloc(offsetof(block_addr, else_addr)); + + if (!block) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " "alloc memory failed"); @@ -2221,10 +2302,11 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } block->block_type = frame_csp->block_type; - block->else_addr = (void*)frame_csp->else_addr; + if (frame_csp->block_type == BLOCK_TYPE_IF) + block->else_addr = (void*)frame_csp->else_addr; block->end_addr = (void*)frame_csp->end_addr; - if (!wasm_hash_map_insert(branch_set, (void*)frame_csp->start_addr, + if (!wasm_hash_map_insert(module->branch_set, (void*)frame_csp->start_addr, block)) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " @@ -2232,6 +2314,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, wasm_free(block); goto fail; } +#endif } break; } @@ -2248,7 +2331,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, block_return_type = (frame_csp - i)->return_type; - if(!wasm_loader_find_block_addr(branch_set, + if(!wasm_loader_find_block_addr(module, (frame_csp - i)->start_addr, p_end, (frame_csp - i)->block_type, @@ -2304,7 +2387,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_TYPE(ret_type); PUSH_TYPE(ret_type); - if(!wasm_loader_find_block_addr(branch_set, + if(!wasm_loader_find_block_addr(module, (frame_csp - 1)->start_addr, p_end, (frame_csp - 1)->block_type, @@ -2862,8 +2945,6 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, return_value = true; fail: - if (frame_lp_ref_bottom) - wasm_free(frame_lp_ref_bottom); if (frame_ref_bottom) wasm_free(frame_ref_bottom); if (frame_csp_bottom) diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_loader.h b/core/iwasm/runtime/vmcore-wasm/wasm_loader.h index 98bc06df13..1a39396053 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_loader.h +++ b/core/iwasm/runtime/vmcore-wasm/wasm_loader.h @@ -61,10 +61,7 @@ wasm_loader_unload(WASMModule *module); * Find address of related else opcode and end opcode of opcode block/loop/if * according to the start address of opcode. * - * @param branch_set the hashtable to store the else/end adress info of - * block/loop/if opcode. The function will lookup the hashtable firstly, - * if not found, it will then search the code from start_addr, and if success, - * stores the result to the hashtable. + * @param module the module to find * @param start_addr the next address of opcode block/loop/if * @param code_end_addr the end address of function code block * @param block_type the type of block, 0/1/2 denotes block/loop/if @@ -76,7 +73,7 @@ wasm_loader_unload(WASMModule *module); * @return true if success, false otherwise */ bool -wasm_loader_find_block_addr(HashMap *map, +wasm_loader_find_block_addr(WASMModule *module, const uint8 *start_addr, const uint8 *code_end_addr, uint8 block_type, diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c index f6c3c5cce1..b12256d37b 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c @@ -706,7 +706,7 @@ execute_start_function(WASMModuleInstance *module_inst) * Instantiate module */ WASMModuleInstance* -wasm_runtime_instantiate(const WASMModule *module, +wasm_runtime_instantiate(WASMModule *module, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) { @@ -726,9 +726,11 @@ wasm_runtime_instantiate(const WASMModule *module, /* Check heap size */ heap_size = align_uint(heap_size, 8); if (heap_size == 0) - heap_size = DEFAULT_WASM_HEAP_SIZE; - if (heap_size < MIN_WASM_HEAP_SIZE) - heap_size = MIN_WASM_HEAP_SIZE; + heap_size = APP_HEAP_SIZE_DEFAULT; + if (heap_size < APP_HEAP_SIZE_MIN) + heap_size = APP_HEAP_SIZE_MIN; + if (heap_size > APP_HEAP_SIZE_MAX) + heap_size = APP_HEAP_SIZE_MAX; /* Instantiate global firstly to get the mutable data size */ global_count = module->import_global_count + module->global_count; @@ -909,7 +911,6 @@ wasm_runtime_instantiate(const WASMModule *module, &module_inst->functions[module->start_function]; } - module_inst->branch_set = module->branch_set; module_inst->module = module; /* module instance type */ diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h index 8a2e87fa0f..649f8308da 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h +++ b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h @@ -25,11 +25,6 @@ extern "C" { #endif - -#define DEFAULT_WASM_STACK_SIZE (8 * 1024) -#define DEFAULT_WASM_HEAP_SIZE (8 * 1024) -#define MIN_WASM_HEAP_SIZE (1 * 1024) - typedef struct WASMMemoryInstance { /* Current page count */ uint32 cur_page_count; @@ -153,8 +148,7 @@ typedef struct WASMModuleInstance { WASMFunctionInstance *start_function; - HashMap *branch_set; - const WASMModule *module; + WASMModule *module; uint32 DYNAMICTOP_PTR_offset; uint32 temp_ret; diff --git a/core/shared-lib/include/bh_memory.h b/core/shared-lib/include/bh_memory.h index c24b132a7c..51312cbf14 100644 --- a/core/shared-lib/include/bh_memory.h +++ b/core/shared-lib/include/bh_memory.h @@ -52,6 +52,8 @@ int bh_memory_init_with_allocator(void *malloc_func, void *free_func); */ void bh_memory_destroy(); +#if BEIHAI_ENABLE_MEMORY_PROFILING == 0 + /** * This function allocates a memory chunk from system * @@ -68,6 +70,32 @@ void* bh_malloc(unsigned int size); */ void bh_free(void *ptr); +#else + +void* bh_malloc_profile(const char *file, int line, const char *func, unsigned int size); +void bh_free_profile(const char *file, int line, const char *func, void *ptr); + +#define bh_malloc(size) bh_malloc_profile(__FILE__, __LINE__, __func__, size) +#define bh_free(ptr) bh_free_profile(__FILE__, __LINE__, __func__, ptr) + +/** + * Print current memory profiling data + * + * @param file file name of the caller + * @param line line of the file of the caller + * @param func function name of the caller + */ +void memory_profile_print(const char *file, int line, const char *func, int alloc); + +/** + * Summarize memory usage and print it out + * Can use awk to analyze the output like below: + * awk -F: '{print $2,$4,$6,$8,$9}' OFS="\t" ./out.txt | sort -n -r -k 1 + */ +void memory_usage_summarize(); + +#endif + #ifdef __cplusplus } #endif diff --git a/core/shared-lib/include/config.h b/core/shared-lib/include/config.h index 8ca0e01e21..e1926a4bb8 100644 --- a/core/shared-lib/include/config.h +++ b/core/shared-lib/include/config.h @@ -48,6 +48,9 @@ /* WASM Interpreter labels-as-values feature */ #define WASM_ENABLE_LABELS_AS_VALUES 1 +/* WASM Branch Block address hashmap */ +#define WASM_ENABLE_HASH_BLOCK_ADDR 0 + /* Heap and stack profiling */ #define BEIHAI_ENABLE_MEMORY_PROFILING 0 @@ -77,14 +80,22 @@ #define WORKING_FLOW_HEAP_SIZE 0 */ -/* Default/min/max heap size of each app */ -#define APP_HEAP_SIZE_DEFAULT (48 * 1024) +/* Default min/max heap size of each app */ +#define APP_HEAP_SIZE_DEFAULT (8 * 1024) #define APP_HEAP_SIZE_MIN (2 * 1024) #define APP_HEAP_SIZE_MAX (1024 * 1024) +/* Default wasm stack size of each app */ +#define DEFAULT_WASM_STACK_SIZE (8 * 1024) + /* Default/min/max stack size of each app thread */ +#ifndef __ZEPHYR__ #define APP_THREAD_STACK_SIZE_DEFAULT (20 * 1024) #define APP_THREAD_STACK_SIZE_MIN (16 * 1024) #define APP_THREAD_STACK_SIZE_MAX (256 * 1024) - +#else +#define APP_THREAD_STACK_SIZE_DEFAULT (4 * 1024) +#define APP_THREAD_STACK_SIZE_MIN (2 * 1024) +#define APP_THREAD_STACK_SIZE_MAX (256 * 1024) +#endif #endif diff --git a/core/shared-lib/mem-alloc/bh_memory.c b/core/shared-lib/mem-alloc/bh_memory.c index 46dd1fd8da..92b1fdd470 100644 --- a/core/shared-lib/mem-alloc/bh_memory.c +++ b/core/shared-lib/mem-alloc/bh_memory.c @@ -14,11 +14,38 @@ * limitations under the License. */ +#include "bh_config.h" #include "bh_memory.h" #include "mem_alloc.h" #include #include +#if BEIHAI_ENABLE_MEMORY_PROFILING != 0 +#include "bh_thread.h" + +/* Memory profile data of a function */ +typedef struct memory_profile { + struct memory_profile *next; + const char *function_name; + const char *file_name; + int line_in_file; + int malloc_num; + int free_num; + int total_malloc; + int total_free; +} memory_profile_t; + +/* Memory in use which grows when bh_malloc was called + * and decreases when bh_free was called */ +static unsigned int memory_in_use = 0; + +/* Memory profile data list */ +static memory_profile_t *memory_profiles_list = NULL; + +/* Lock of the memory profile list */ +static korp_mutex profile_lock; +#endif + #ifndef MALLOC_MEMORY_FROM_SYSTEM typedef enum Memory_Mode { @@ -39,6 +66,9 @@ int bh_memory_init_with_pool(void *mem, unsigned int bytes) if (_allocator) { memory_mode = MEMORY_MODE_POOL; pool_allocator = _allocator; +#if BEIHAI_ENABLE_MEMORY_PROFILING != 0 + vm_mutex_init(&profile_lock); +#endif return 0; } printf("Init memory with pool (%p, %u) failed.\n", mem, bytes); @@ -51,6 +81,9 @@ int bh_memory_init_with_allocator(void *_malloc_func, void *_free_func) memory_mode = MEMORY_MODE_ALLOCATOR; malloc_func = _malloc_func; free_func = _free_func; +#if BEIHAI_ENABLE_MEMORY_PROFILING != 0 + vm_mutex_init(&profile_lock); +#endif return 0; } printf("Init memory with allocator (%p, %p) failed.\n", _malloc_func, @@ -60,12 +93,15 @@ int bh_memory_init_with_allocator(void *_malloc_func, void *_free_func) void bh_memory_destroy() { +#if BEIHAI_ENABLE_MEMORY_PROFILING != 0 + vm_mutex_destroy(&profile_lock); +#endif if (memory_mode == MEMORY_MODE_POOL) mem_allocator_destroy(pool_allocator); memory_mode = MEMORY_MODE_UNKNOWN; } -void* bh_malloc(unsigned int size) +void* bh_malloc_internal(unsigned int size) { if (memory_mode == MEMORY_MODE_UNKNOWN) { printf("bh_malloc failed: memory hasn't been initialize.\n"); @@ -77,7 +113,7 @@ void* bh_malloc(unsigned int size) } } -void bh_free(void *ptr) +void bh_free_internal(void *ptr) { if (memory_mode == MEMORY_MODE_UNKNOWN) { printf("bh_free failed: memory hasn't been initialize.\n"); @@ -88,8 +124,157 @@ void bh_free(void *ptr) } } +#if BEIHAI_ENABLE_MEMORY_PROFILING != 0 +void* bh_malloc_profile(const char *file, + int line, + const char *func, + unsigned int size) +{ + void *p = bh_malloc_internal(size + 8); + + if (p) { + memory_profile_t *profile; + + vm_mutex_lock(&profile_lock); + + profile = memory_profiles_list; + while (profile) { + if (strcmp(profile->function_name, func) == 0 + && strcmp(profile->file_name, file) == 0) { + break; + } + profile = profile->next; + } + + if (profile) { + profile->total_malloc += size;/* TODO: overflow check */ + profile->malloc_num++; + } else { + profile = bh_malloc_internal(sizeof(memory_profile_t)); + if (!profile) { + vm_mutex_unlock(&profile_lock); + memcpy(p, &size, sizeof(size)); + return (char *)p + 8; + } + + memset(profile, 0, sizeof(memory_profile_t)); + profile->file_name = file; + profile->line_in_file = line; + profile->function_name = func; + profile->malloc_num = 1; + profile->total_malloc = size; + profile->next = memory_profiles_list; + memory_profiles_list = profile; + } + + vm_mutex_unlock(&profile_lock); + + memcpy(p, &size, sizeof(size)); + memory_in_use += size; + + memory_profile_print(file, line, func, size); + + return (char *)p + 8; + } + + return NULL; +} + +void bh_free_profile(const char *file, int line, const char *func, void *ptr) +{ + unsigned int size = *(unsigned int *)((char *)ptr - 8); + memory_profile_t *profile; + + bh_free_internal((char *)ptr - 8); + + if (memory_in_use >= size) + memory_in_use -= size; + + vm_mutex_lock(&profile_lock); + + profile = memory_profiles_list; + while (profile) { + if (strcmp(profile->function_name, func) == 0 + && strcmp(profile->file_name, file) == 0) { + break; + } + profile = profile->next; + } + + if (profile) { + profile->total_free += size;/* TODO: overflow check */ + profile->free_num++; + } else { + profile = bh_malloc_internal(sizeof(memory_profile_t)); + if (!profile) { + vm_mutex_unlock(&profile_lock); + return; + } + + memset(profile, 0, sizeof(memory_profile_t)); + profile->file_name = file; + profile->line_in_file = line; + profile->function_name = func; + profile->free_num = 1; + profile->total_free = size; + profile->next = memory_profiles_list; + memory_profiles_list = profile; + } + + vm_mutex_unlock(&profile_lock); +} + +/** + * Summarize memory usage and print it out + * Can use awk to analyze the output like below: + * awk -F: '{print $2,$4,$6,$8,$9}' OFS="\t" ./out.txt | sort -n -r -k 1 + */ +void memory_usage_summarize() +{ + memory_profile_t *profile; + + vm_mutex_lock(&profile_lock); + + profile = memory_profiles_list; + while (profile) { + printf("malloc:%d:malloc_num:%d:free:%d:free_num:%d:%s\n", + profile->total_malloc, + profile->malloc_num, + profile->total_free, + profile->free_num, + profile->function_name); + profile = profile->next; + } + + vm_mutex_unlock(&profile_lock); +} + +void memory_profile_print(const char *file, + int line, + const char *func, + int alloc) +{ + printf("location:%s@%d:used:%d:contribution:%d\n", + func, line, memory_in_use, alloc); +} + +#else + +void* bh_malloc(unsigned int size) +{ + return bh_malloc_internal(size); +} + +void bh_free(void *ptr) +{ + bh_free_internal(ptr); +} +#endif + #else /* else of MALLOC_MEMORY_FROM_SYSTEM */ +#if BEIHAI_ENABLE_MEMORY_PROFILING == 0 + void* bh_malloc(unsigned int size) { return malloc(size); @@ -98,8 +283,36 @@ void* bh_malloc(unsigned int size) void bh_free(void *ptr) { if (ptr) - free(ptr); + free(ptr); +} + +#else /* else of BEIHAI_ENABLE_MEMORY_PROFILING */ + +void* bh_malloc_profile(const char *file, + int line, + const char *func, + unsigned int size) +{ + (void)file; + (void)line; + (void)func; + + (void)memory_profiles_list; + (void)profile_lock; + (void)memory_in_use; + + return malloc(size); } +void bh_free_profile(const char *file, int line, const char *func, void *ptr) +{ + (void)file; + (void)line; + (void)func; + + if (ptr) + free(ptr); +} +#endif /* end of BEIHAI_ENABLE_MEMORY_PROFILING */ #endif /* end of MALLOC_MEMORY_FROM_SYSTEM*/ diff --git a/core/shared-lib/platform/linux/bh_thread.c b/core/shared-lib/platform/linux/bh_thread.c index 9d45b147f0..201c9b5e68 100755 --- a/core/shared-lib/platform/linux/bh_thread.c +++ b/core/shared-lib/platform/linux/bh_thread.c @@ -128,7 +128,7 @@ int _vm_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg, unsigned int stack_size) { return _vm_thread_create_with_prio(tid, start, arg, stack_size, - BH_THREAD_DEFAULT_PRIORITY); + BH_THREAD_DEFAULT_PRIORITY); } korp_tid _vm_self_thread() diff --git a/doc/memory_usage.txt b/doc/memory_usage.txt new file mode 100644 index 0000000000..ecc64a9715 --- /dev/null +++ b/doc/memory_usage.txt @@ -0,0 +1,13 @@ +Current memory usage, take samples/littlevgl in Zephyr for example: +(1) WASM app binary: 142K for littlevgl ui_app.wasm +(2) WASM app memory space: 64K for littlevgl ui_app.wasm +(3) WASM app heap space: 8K by default +(4) WASM app thread native stack: 4K by default +(5) WASM interpreter stack: 8K by default +(6) WASM block address hash cache: 3K +(7) timer thread stack: 4K +(8) sensor thread stack: 4K +(9) touch screen thread stack: 4K +(10) others: vm, app mgr, queue, native lib: ~22K + +Total memory usage: ~263K diff --git a/samples/littlevgl/README.md b/samples/littlevgl/README.md index 81db08863b..006b6624c6 100644 --- a/samples/littlevgl/README.md +++ b/samples/littlevgl/README.md @@ -75,7 +75,7 @@ https://docs.zephyrproject.org/latest/getting_started/index.html
However, nucleo_f767zi is almost the same as nucleo_f746zg, except FLASH and SRAM size. So we changed the DTS setting of nucleo_f746zg boards for a workaround.
- `Modify zephyr/dts/arm/st/f7/stm32f746xg.dtsi, change DT_SIZE_K(320) to DT_SIZE_K(512)`
+ `Modify zephyr/dts/arm/st/f7/stm32f746Xg.dtsi, change DT_SIZE_K(320) to DT_SIZE_K(512)`
`mkdir build && cd build`
`source ../../../../zephyr-env.sh`
`cmake -GNinja -DBOARD=nucleo_f746zg ..`
diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c index cbb894100e..c5d23b0579 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c @@ -342,7 +342,7 @@ static host_interface interface = { .send = uart_send, .destroy = uart_destroy } #endif -static char global_heap_buf[1024 * 1024] = { 0 }; +static char global_heap_buf[270 * 1024] = { 0 }; static void showUsage() { diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c index 5d408b562d..6d9048d4df 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c @@ -152,7 +152,7 @@ void xpt2046_init(void) return; } gpio_pin_configure(xpt2046_cs_ctrl.gpio_dev, XPT2046_CS_GPIO_PIN, - GPIO_DIR_OUT); + GPIO_DIR_OUT); gpio_pin_write(xpt2046_cs_ctrl.gpio_dev, XPT2046_CS_GPIO_PIN, 1); xpt2046_cs_ctrl.gpio_pin = XPT2046_CS_GPIO_PIN; xpt2046_cs_ctrl.delay = 0; @@ -169,14 +169,15 @@ void xpt2046_init(void) } /* Setup GPIO input */ ret = gpio_pin_configure(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN, - (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW - | GPIO_INT_DEBOUNCE)); + (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE + | GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE) + ); if (ret) { printk("Error configuring pin %d!\n", XPT2046_PEN_GPIO_PIN); } gpio_init_callback(&gpio_cb, xpt2046_pen_gpio_callback, - BIT(XPT2046_PEN_GPIO_PIN)); + BIT(XPT2046_PEN_GPIO_PIN)); ret = gpio_add_callback(xpt2046_pen_gpio_dev, &gpio_cb); if (ret) { @@ -191,10 +192,10 @@ void xpt2046_init(void) k_sem_init(&sem_touch_read, 0, 1); k_thread_create(&touch_thread_data, touch_read_thread_stack, - TOUCH_READ_THREAD_STACK_SIZE, touch_screen_read_thread, NULL, NULL, NULL, 5, - 0, K_NO_WAIT); + TOUCH_READ_THREAD_STACK_SIZE, touch_screen_read_thread, + NULL, NULL, NULL, 5, + 0, K_NO_WAIT); printf("xpt2046_init ok \n"); - } /** diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c index dc0d745c39..1fc3eb941d 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c @@ -43,7 +43,6 @@ static void uart_irq_callback(struct device *dev) int size = 0; while (uart_poll_in(dev, &ch) == 0) { - uart_char_cnt++; aee_host_msg_callback(&ch, 1); } @@ -66,24 +65,27 @@ static bool host_init() int host_send(void * ctx, const char *buf, int size) { for (int i = 0; i < size; i++) - uart_poll_out(uart_dev, buf[i]); + uart_poll_out(uart_dev, buf[i]); return size; } void host_destroy() { - } +host_interface interface = { + .init = host_init, + .send = host_send, + .destroy = host_destroy +}; -#define DEFAULT_THREAD_STACKSIZE (8 * 1024) - -host_interface interface = { .init = host_init, .send = - host_send, .destroy = host_destroy }; timer_ctx_t timer_ctx; -static char global_heap_buf[ 498*1024] = { 0 }; + +static char global_heap_buf[270 * 1024] = { 0 }; + extern void display_init(void); + int iwasm_main() { korp_thread tid, tm_tid; @@ -108,6 +110,7 @@ int iwasm_main() // TODO: app_manager_startup(&interface); - fail1: bh_memory_destroy(); +fail1: + bh_memory_destroy(); return -1; } diff --git a/samples/littlevgl/wasm-apps/Makefile_wasm_app b/samples/littlevgl/wasm-apps/Makefile_wasm_app index 801aed4adf..dcf7f17243 100644 --- a/samples/littlevgl/wasm-apps/Makefile_wasm_app +++ b/samples/littlevgl/wasm-apps/Makefile_wasm_app @@ -50,6 +50,6 @@ SRCS += ../../../core/iwasm/lib/app-libs/base/timer.c all: @$(CC) $(CFLAGS) $(SRCS) \ -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ - -s TOTAL_MEMORY=131072 -s TOTAL_STACK=8096 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=2048\ -s "EXPORTED_FUNCTIONS=['_on_init', '_on_request', '_on_sensor_event', '_on_timer_callback']" \ -o ui_app.wasm From f32965bb5948d479cdcd3f8482092908f7d31724 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Fri, 31 May 2019 14:15:44 +0800 Subject: [PATCH 2/3] Implement memory.grow and limit heap space base offset to 1G; modify iwasm build type to Release and 64 bit by default --- README.md | 2 +- core/iwasm/products/linux/CMakeLists.txt | 9 +- core/iwasm/products/linux/main.c | 41 ++-- core/iwasm/runtime/vmcore-wasm/wasm_interp.c | 65 +++--- core/iwasm/runtime/vmcore-wasm/wasm_loader.c | 24 ++- core/iwasm/runtime/vmcore-wasm/wasm_runtime.c | 186 +++++++++++------- core/iwasm/runtime/vmcore-wasm/wasm_runtime.h | 18 +- core/shared-lib/include/bh_memory.h | 6 + core/shared-lib/include/config.h | 9 + core/shared-lib/mem-alloc/bh_memory.c | 15 +- core/shared-lib/platform/linux/bh_thread.c | 2 +- 11 files changed, 237 insertions(+), 140 deletions(-) diff --git a/README.md b/README.md index 1fe9e8bf69..2e85545277 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ cd iwasm/products/linux/bin You will get the following output: ``` Hello world! -buf ptr: 0x000101ac +buf ptr: 0x400002b0 buf: 1234 ``` If you would like to run the test app on Zephyr, we have embedded a test sample into its OS image. You will need to execute: diff --git a/core/iwasm/products/linux/CMakeLists.txt b/core/iwasm/products/linux/CMakeLists.txt index 72926661bb..a2510790e4 100644 --- a/core/iwasm/products/linux/CMakeLists.txt +++ b/core/iwasm/products/linux/CMakeLists.txt @@ -29,8 +29,8 @@ if (NOT ("$ENV{VALGRIND}" STREQUAL "YES")) add_definitions(-DNVALGRIND) endif () -# Currently build as 32-bit by default. -set (BUILD_AS_64BIT_SUPPORT "NO") +# Currently build as 64-bit by default. +set (BUILD_AS_64BIT_SUPPORT "YES") if (CMAKE_SIZEOF_VOID_P EQUAL 8) if (${BUILD_AS_64BIT_SUPPORT} STREQUAL "YES") @@ -44,6 +44,11 @@ else () endif () endif () +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif (NOT CMAKE_BUILD_TYPE) +message ("CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections -Wall -Wno-unused-parameter -Wno-pedantic") diff --git a/core/iwasm/products/linux/main.c b/core/iwasm/products/linux/main.c index 7a87d8b0a7..22fe692c0e 100644 --- a/core/iwasm/products/linux/main.c +++ b/core/iwasm/products/linux/main.c @@ -35,15 +35,14 @@ static int print_help() { wasm_printf("Usage: iwasm [-options] wasm_file [args...]\n"); wasm_printf("options:\n"); - wasm_printf(" -f|--function name Specify function name to run " - "in module rather than main\n"); + wasm_printf(" -f|--function name Specify function name to run in module\n" + " rather than main\n"); #if WASM_ENABLE_LOG != 0 - wasm_printf( - " -v=X Set log verbose level (0 to 2, default is 1), larger level with more log\n"); + wasm_printf(" -v=X Set log verbose level (0 to 2, default is 1),\n" + " larger level with more log\n"); #endif - wasm_printf( - " --repl Start a very simple REPL (read-eval-print-loop) mode \n" - " that runs commands in the form of `FUNC ARG...`\n"); + wasm_printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" + " that runs commands in the form of `FUNC ARG...`\n"); return 1; } @@ -64,7 +63,7 @@ app_instance_func(wasm_module_inst_t module_inst, const char *func_name) const char *exception; wasm_application_execute_func(module_inst, func_name, app_argc - 1, - app_argv + 1); + app_argv + 1); if ((exception = wasm_runtime_get_exception(module_inst))) wasm_printf("%s\n", exception); return NULL; @@ -122,7 +121,7 @@ app_instance_repl(wasm_module_inst_t module_inst) } if (app_argc != 0) { wasm_application_execute_func(module_inst, app_argv[0], - app_argc - 1, app_argv + 1); + app_argc - 1, app_argv + 1); } free(app_argv); } @@ -177,7 +176,7 @@ int main(int argc, char *argv[]) app_argv = argv; if (bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)) - != 0) { + != 0) { wasm_printf("Init global heap failed.\n"); return -1; } @@ -190,19 +189,22 @@ int main(int argc, char *argv[]) /* load WASM byte buffer from WASM bin file */ if (!(wasm_file_buf = (uint8*) wasm_read_file_to_buffer(wasm_file, - &wasm_file_size))) + &wasm_file_size))) goto fail2; /* load WASM module */ if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, - error_buf, sizeof(error_buf)))) { + error_buf, sizeof(error_buf)))) { wasm_printf("%s\n", error_buf); goto fail3; } /* instantiate the module */ - if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, 8 * 1024, - 8 * 1024, error_buf, sizeof(error_buf)))) { + if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, + 16 * 1024, /* stack size */ + 8 * 1024, /* heap size */ + error_buf, + sizeof(error_buf)))) { wasm_printf("%s\n", error_buf); goto fail4; } @@ -217,21 +219,20 @@ int main(int argc, char *argv[]) /* destroy the module instance */ wasm_runtime_deinstantiate(wasm_module_inst); - fail4: +fail4: /* unload the module */ wasm_runtime_unload(wasm_module); - fail3: +fail3: /* free the file buffer */ wasm_free(wasm_file_buf); - fail2: +fail2: /* destroy runtime environment */ wasm_runtime_destroy(); - fail1: bh_memory_destroy(); - - (void) func_name; +fail1: + bh_memory_destroy(); return 0; } diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_interp.c b/core/iwasm/runtime/vmcore-wasm/wasm_interp.c index ab715a477e..73163f32ca 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_interp.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_interp.c @@ -74,26 +74,28 @@ GET_F64_FROM_ADDR (uint32 *addr) } #endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ -#define is_valid_addr(memory, heap, addr) \ - (memory->base_addr <= addr && addr <= memory->end_addr) \ - #define CHECK_MEMORY_OVERFLOW() do { \ + uint32 offset1 = offset + addr; \ uint8 *maddr1; \ if (flags != 2) \ LOG_VERBOSE("unaligned load/store in wasm interp, flag is: %d.\n", flags);\ - if (offset + addr < addr) { \ - wasm_runtime_set_exception(module, "out of bounds memory access"); \ - goto got_exception; \ - } \ - maddr = memory->memory_data + (offset + addr); \ - if (!is_valid_addr(memory, NULL, maddr)) { \ - wasm_runtime_set_exception(module, "out of bounds memory access"); \ - goto got_exception; \ + if (offset1 < offset) \ + goto out_of_bounds; \ + if (offset1 < heap_base_offset) { \ + maddr = memory->memory_data + offset1; \ + if (maddr < memory->base_addr) \ + goto out_of_bounds; \ + maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \ + if (maddr1 > memory->end_addr) \ + goto out_of_bounds; \ } \ - maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \ - if (!is_valid_addr(memory, NULL, maddr1)) { \ - wasm_runtime_set_exception(module, "out of bounds memory access"); \ - goto got_exception; \ + else { \ + maddr = memory->heap_data + offset1 - memory->heap_base_offset; \ + if (maddr < memory->heap_data) \ + goto out_of_bounds; \ + maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \ + if (maddr1 > memory->heap_data_end) \ + goto out_of_bounds; \ } \ } while (0) @@ -712,6 +714,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, { WASMModuleInstance *module = self->module_inst; WASMMemoryInstance *memory = module->default_memory; + int32 heap_base_offset = memory ? memory->heap_base_offset : 0; WASMTableInstance *table = module->default_table; uint8 opcode_IMPDEP2 = WASM_OP_IMPDEP2; WASMInterpFrame *frame = NULL; @@ -1247,26 +1250,25 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP (WASM_OP_MEMORY_GROW): { - uint32 reserved, prev_page_count, delta, tmp; + uint32 reserved, delta, prev_page_count = memory->cur_page_count; read_leb_uint32(frame_ip, frame_ip_end, reserved); - prev_page_count = memory->cur_page_count; delta = POP_I32(); - PUSH_I32(prev_page_count); - if (delta == 0) - HANDLE_OP_END (); - else if (delta + prev_page_count > memory->max_page_count || - delta + prev_page_count < prev_page_count) { - tmp = POP_I32(); + + if (!wasm_runtime_enlarge_memory(module, delta)) { + /* fail to memory.grow, return -1 */ PUSH_I32(-1); - (void)tmp; - HANDLE_OP_END (); + if (wasm_runtime_get_exception(module)) { + printf("%s\n", wasm_runtime_get_exception(module)); + wasm_runtime_set_exception(module, NULL); + } + } + else { + /* success, return previous page count */ + PUSH_I32(prev_page_count); + /* update the memory instance ptr */ + memory = module->default_memory; } - - if (!wasm_runtime_enlarge_memory(module, delta)) - goto got_exception; - - memory = module->default_memory; (void)reserved; HANDLE_OP_END (); @@ -2093,6 +2095,9 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP_END (); } + out_of_bounds: + wasm_runtime_set_exception(module, "out of bounds memory access"); + got_exception: if (depths && depths != depth_buf) { wasm_free(depths); diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_loader.c b/core/iwasm/runtime/vmcore-wasm/wasm_loader.c index 1af9278e1e..c03ddc3a31 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_loader.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_loader.c @@ -314,14 +314,20 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; + uint32 pool_size = bh_memory_pool_size(); + uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT + / NumBytesPerPage; read_leb_uint32(p, p_end, memory->flags); read_leb_uint32(p, p_end, memory->init_page_count); - if (memory->flags & 1) + if (memory->flags & 1) { read_leb_uint32(p, p_end, memory->max_page_count); + if (memory->max_page_count > max_page_count) + memory->max_page_count = max_page_count; + } else - /* Limit the maximum memory size to 4GB */ - memory->max_page_count = 0x10000; + /* Limit the maximum memory size to max_page_count */ + memory->max_page_count = max_page_count; *p_buf = p; return true; @@ -351,14 +357,20 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; + uint32 pool_size = bh_memory_pool_size(); + uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT + / NumBytesPerPage; read_leb_uint32(p, p_end, memory->flags); read_leb_uint32(p, p_end, memory->init_page_count); - if (memory->flags & 1) + if (memory->flags & 1) { read_leb_uint32(p, p_end, memory->max_page_count); + if (memory->max_page_count > max_page_count) + memory->max_page_count = max_page_count; + } else - /* Limit the maximum memory size to 4GB */ - memory->max_page_count = 0x10000; + /* Limit the maximum memory size to max_page_count */ + memory->max_page_count = max_page_count; *p_buf = p; return true; diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c index b12256d37b..ebfe14b57d 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c @@ -163,6 +163,7 @@ memories_deinstantiate(WASMMemoryInstance **memories, uint32 count) if (memories[i]) { if (memories[i]->heap_handle) mem_allocator_destroy(memories[i]->heap_handle); + wasm_free(memories[i]->heap_data); wasm_free(memories[i]); } wasm_free(memories); @@ -177,10 +178,10 @@ memory_instantiate(uint32 init_page_count, uint32 max_page_count, { WASMMemoryInstance *memory; uint32 total_size = offsetof(WASMMemoryInstance, base_addr) + - NumBytesPerPage * init_page_count + - addr_data_size + global_data_size + - heap_size; + NumBytesPerPage * init_page_count + + addr_data_size + global_data_size; + /* Allocate memory space, addr data and global data */ if (!(memory = wasm_malloc(total_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: allocate memory failed."); @@ -190,28 +191,46 @@ memory_instantiate(uint32 init_page_count, uint32 max_page_count, memset(memory, 0, total_size); memory->cur_page_count = init_page_count; memory->max_page_count = max_page_count; + memory->addr_data = memory->base_addr; memory->addr_data_size = addr_data_size; memory->memory_data = memory->addr_data + addr_data_size; - memory->heap_data = memory->memory_data + - NumBytesPerPage * memory->cur_page_count;; - memory->heap_data_size = heap_size; - - memory->global_data = memory->heap_data + memory->heap_data_size; + memory->global_data = memory->memory_data + + NumBytesPerPage * memory->cur_page_count;; memory->global_data_size = global_data_size; memory->end_addr = memory->global_data + global_data_size; + /* Allocate heap space */ + if (!(memory->heap_data = wasm_malloc(heap_size))) { + set_error_buf(error_buf, error_buf_size, + "Instantiate memory failed: allocate memory failed."); + goto fail1; + } + memory->heap_data_end = memory->heap_data + heap_size; + /* Initialize heap */ if (!(memory->heap_handle = mem_allocator_create - (memory->heap_data, memory->heap_data_size))) { - wasm_free(memory); - return NULL; + (memory->heap_data, heap_size))) { + goto fail2; } +#if WASM_ENABLE_MEMORY_GROW != 0 + memory->heap_base_offset = DEFAULT_APP_HEAP_BASE_OFFSET; +#else + memory->heap_base_offset = memory->end_addr - memory->memory_data; +#endif + return memory; + +fail2: + wasm_free(memory->heap_data); + +fail1: + wasm_free(memory); + return NULL; } /** @@ -975,58 +994,65 @@ wasm_runtime_deinstantiate(WASMModuleInstance *module_inst) bool wasm_runtime_enlarge_memory(WASMModuleInstance *module, int inc_page_count) { -#if 1 - wasm_runtime_set_exception(module, "unsupported operation: enlarge memory."); - return false; -#else +#if WASM_ENABLE_MEMORY_GROW != 0 WASMMemoryInstance *memory = module->default_memory; WASMMemoryInstance *new_memory; uint32 total_page_count = inc_page_count + memory->cur_page_count; uint32 total_size = offsetof(WASMMemoryInstance, base_addr) + memory->addr_data_size + NumBytesPerPage * total_page_count + - memory->global_data_size + - memory->thunk_argv_data_size + - sizeof(uint32) * memory->thunk_argc; + memory->global_data_size; + + if (inc_page_count <= 0) + /* No need to enlarge memory */ + return true; + + if (total_page_count < memory->cur_page_count /* integer overflow */ + || total_page_count > memory->max_page_count) { + wasm_runtime_set_exception(module, "fail to enlarge memory."); + return false; + } if (!(new_memory = wasm_malloc(total_size))) { - wasm_runtime_set_exception(module, "alloc memory for enlarge memory failed."); + wasm_runtime_set_exception(module, "fail to enlarge memory."); return false; } new_memory->cur_page_count = total_page_count; - new_memory->max_page_count = memory->max_page_count > total_page_count - ? memory->max_page_count : total_page_count; + new_memory->max_page_count = memory->max_page_count; + new_memory->addr_data = new_memory->base_addr; new_memory->addr_data_size = memory->addr_data_size; - new_memory->thunk_argv_data = new_memory->addr_data + memory->addr_data_size; - new_memory->thunk_argv_data_size = memory->thunk_argv_data_size; - new_memory->thunk_argc = memory->thunk_argc; - new_memory->thunk_argv_offsets = new_memory->thunk_argv_data + - memory->thunk_argv_data_size; + new_memory->memory_data = new_memory->addr_data + new_memory->addr_data_size; - new_memory->memory_data = new_memory->thunk_argv_offsets + - sizeof(uint32) * memory->thunk_argc; new_memory->global_data = new_memory->memory_data + - NumBytesPerPage * new_memory->cur_page_count; + NumBytesPerPage * total_page_count; new_memory->global_data_size = memory->global_data_size; new_memory->end_addr = new_memory->global_data + memory->global_data_size; - /* Copy addr data, thunk argv data, thunk argv offsets and memory data */ + /* Copy addr data and memory data */ memcpy(new_memory->addr_data, memory->addr_data, memory->global_data - memory->addr_data); /* Copy global data */ memcpy(new_memory->global_data, memory->global_data, - memory->end_addr - memory->global_data); + memory->global_data_size); /* Init free space of new memory */ memset(new_memory->memory_data + NumBytesPerPage * memory->cur_page_count, - 0, NumBytesPerPage * (total_page_count - memory->cur_page_count)); + 0, NumBytesPerPage * (total_page_count - memory->cur_page_count)); + + new_memory->heap_data = memory->heap_data; + new_memory->heap_data_end = memory->heap_data_end; + new_memory->heap_handle = memory->heap_handle; + new_memory->heap_base_offset = memory->heap_base_offset; - wasm_free(memory); module->memories[0] = module->default_memory = new_memory; + wasm_free(memory); return true; +#else + wasm_runtime_set_exception(module, "unsupported operation: enlarge memory."); + return false; #endif } @@ -1098,29 +1124,29 @@ wasm_runtime_get_current_module_inst() int32 wasm_runtime_module_malloc(WASMModuleInstance *module_inst, uint32 size) { - uint8 *memory_base = module_inst->default_memory->memory_data; - void *heap = module_inst->default_memory->heap_handle; - uint8 *addr = mem_allocator_malloc(heap, size); - if (!addr) + WASMMemoryInstance *memory = module_inst->default_memory; + uint8 *addr = mem_allocator_malloc(memory->heap_handle, size); + if (!addr) { wasm_runtime_set_exception(module_inst, "out of memory"); - return addr ? addr - memory_base : 0; + return 0; + } + return memory->heap_base_offset + (addr - memory->heap_data); } void wasm_runtime_module_free(WASMModuleInstance *module_inst, int32 ptr) { - uint8 *memory_base = module_inst->default_memory->memory_data; - uint8 *heap_base = module_inst->default_memory->heap_data; - uint32 heap_size = module_inst->default_memory->heap_data_size; - void *heap = module_inst->default_memory->heap_handle; - uint8 *addr = ptr ? memory_base + ptr : NULL; - if (addr && (heap_base < addr && addr < heap_base + heap_size)) - mem_allocator_free(heap, addr); + if (ptr) { + WASMMemoryInstance *memory = module_inst->default_memory; + uint8 *addr = memory->heap_data + (ptr - memory->heap_base_offset); + if (memory->heap_data < addr && addr < memory->heap_data_end) + mem_allocator_free(memory->heap_handle, addr); + } } - int32 +int32 wasm_runtime_module_dup_data(WASMModuleInstance *module_inst, - const char *src, uint32 size) + const char *src, uint32 size) { int32 buffer_offset = wasm_runtime_module_malloc(module_inst, size); if (buffer_offset != 0) { @@ -1135,22 +1161,32 @@ bool wasm_runtime_validate_app_addr(WASMModuleInstance *module_inst, int32 app_offset, uint32 size) { + WASMMemoryInstance *memory; + uint8 *addr; + /* integer overflow check */ if(app_offset < 0 || - app_offset + size < size) { - wasm_runtime_set_exception(module_inst, "out of bounds memory access"); - return false; + app_offset + size < app_offset) { + goto fail; } - uint8 *memory_base = module_inst->default_memory->memory_data; - uint8 *addr = memory_base + app_offset; - uint8 *base_addr = module_inst->default_memory->base_addr; - uint8 *end_addr = module_inst->default_memory->end_addr; - bool ret = (base_addr <= addr - && addr + size <= end_addr); - if (!ret) - wasm_runtime_set_exception(module_inst, "out of bounds memory access"); - return ret; + memory = module_inst->default_memory; + if (app_offset < memory->heap_base_offset) { + addr = memory->memory_data + app_offset; + if (!(memory->base_addr <= addr && addr + size <= memory->end_addr)) + goto fail; + return true; + } + else { + addr = memory->heap_data + (app_offset - memory->heap_base_offset); + if (!(memory->heap_data <= addr && addr + size <= memory->heap_data_end)) + goto fail; + return true; + } + +fail: + wasm_runtime_set_exception(module_inst, "out of bounds memory access"); + return false; } bool @@ -1158,26 +1194,42 @@ wasm_runtime_validate_native_addr(WASMModuleInstance *module_inst, void *native_ptr, uint32 size) { uint8 *addr = native_ptr; - uint8 *base_addr = module_inst->default_memory->base_addr; - uint8 *end_addr = module_inst->default_memory->end_addr; - bool ret = (base_addr <= addr && addr + size <= end_addr); - if (!ret || (addr + size < addr)/* integer overflow */) - wasm_runtime_set_exception(module_inst, "out of bounds memory access"); - return ret; + WASMMemoryInstance *memory = module_inst->default_memory; + + if (addr + size < addr) { + goto fail; + } + + if ((memory->base_addr <= addr && addr + size <= memory->end_addr) + || (memory->heap_data <= addr && addr + size <= memory->heap_data_end)) + return true; + +fail: + wasm_runtime_set_exception(module_inst, "out of bounds memory access"); + return false; } void * wasm_runtime_addr_app_to_native(WASMModuleInstance *module_inst, int32 app_offset) { - return module_inst->default_memory->memory_data + app_offset; + WASMMemoryInstance *memory = module_inst->default_memory; + if (app_offset < memory->heap_base_offset) + return memory->memory_data + app_offset; + else + return memory->heap_data + (app_offset - memory->heap_base_offset); } int32 wasm_runtime_addr_native_to_app(WASMModuleInstance *module_inst, void *native_ptr) { - return (uint8*)native_ptr - module_inst->default_memory->memory_data; + WASMMemoryInstance *memory = module_inst->default_memory; + if ((uint8*)native_ptr < memory->heap_data) + return (uint8*)native_ptr - memory->memory_data; + else + return memory->heap_base_offset + + ((uint8*)native_ptr - memory->heap_data); } uint32 diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h index 649f8308da..56e806b94c 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h +++ b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h @@ -37,20 +37,14 @@ typedef struct WASMMemoryInstance { /* Size of addr_data */ uint32 addr_data_size; - /* Thunk data of argument strings */ - uint8 *thunk_argv_data; - uint32 thunk_argv_data_size; - /* Thunk argument count */ - uint32 thunk_argc; - /* Thunk argument offsets */ - uint8 *thunk_argv_offsets; - - /* Heap data */ + /* Heap data base address */ uint8 *heap_data; - /* Heap size */ - uint32 heap_data_size; + /* Heap data end address */ + uint8 *heap_data_end; /* The heap created */ void *heap_handle; + /* Heap base offset of wasm app */ + int32 heap_base_offset; /* Memory data */ uint8 *memory_data; @@ -63,7 +57,7 @@ typedef struct WASMMemoryInstance { /* Base address, the layout is: addr_data + thunk_argv data + thunk arg offsets + - heap data + memory data + global data + memory data + global data memory data init size is: NumBytesPerPage * cur_page_count addr data size and global data size is calculated in module instantiating Note: when memory is re-allocated, the addr data, thunk argv data, thunk diff --git a/core/shared-lib/include/bh_memory.h b/core/shared-lib/include/bh_memory.h index 51312cbf14..352137a347 100644 --- a/core/shared-lib/include/bh_memory.h +++ b/core/shared-lib/include/bh_memory.h @@ -52,6 +52,12 @@ int bh_memory_init_with_allocator(void *malloc_func, void *free_func); */ void bh_memory_destroy(); +/** + * Get the pool size of memory, if memory is initialized with allocator, + * return 1GB by default. + */ +int bh_memory_pool_size(); + #if BEIHAI_ENABLE_MEMORY_PROFILING == 0 /** diff --git a/core/shared-lib/include/config.h b/core/shared-lib/include/config.h index e1926a4bb8..0c270cbc70 100644 --- a/core/shared-lib/include/config.h +++ b/core/shared-lib/include/config.h @@ -80,6 +80,15 @@ #define WORKING_FLOW_HEAP_SIZE 0 */ +/* Support memory.grow opcode and enlargeMemory function */ +#define WASM_ENABLE_MEMORY_GROW 1 + +/* The max percentage of global heap that app memory space can grow */ +#define APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT 1 / 3 + +/* Default base offset of app heap space */ +#define DEFAULT_APP_HEAP_BASE_OFFSET (1 * BH_GB) + /* Default min/max heap size of each app */ #define APP_HEAP_SIZE_DEFAULT (8 * 1024) #define APP_HEAP_SIZE_MIN (2 * 1024) diff --git a/core/shared-lib/mem-alloc/bh_memory.c b/core/shared-lib/mem-alloc/bh_memory.c index 92b1fdd470..bca6970518 100644 --- a/core/shared-lib/mem-alloc/bh_memory.c +++ b/core/shared-lib/mem-alloc/bh_memory.c @@ -49,7 +49,9 @@ static korp_mutex profile_lock; #ifndef MALLOC_MEMORY_FROM_SYSTEM typedef enum Memory_Mode { - MEMORY_MODE_UNKNOWN = 0, MEMORY_MODE_POOL, MEMORY_MODE_ALLOCATOR + MEMORY_MODE_UNKNOWN = 0, + MEMORY_MODE_POOL, + MEMORY_MODE_ALLOCATOR } Memory_Mode; static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN; @@ -59,6 +61,8 @@ static mem_allocator_t pool_allocator = NULL; static void *(*malloc_func)(unsigned int size) = NULL; static void (*free_func)(void *ptr) = NULL; +static unsigned int global_pool_size; + int bh_memory_init_with_pool(void *mem, unsigned int bytes) { mem_allocator_t _allocator = mem_allocator_create(mem, bytes); @@ -69,6 +73,7 @@ int bh_memory_init_with_pool(void *mem, unsigned int bytes) #if BEIHAI_ENABLE_MEMORY_PROFILING != 0 vm_mutex_init(&profile_lock); #endif + global_pool_size = bytes; return 0; } printf("Init memory with pool (%p, %u) failed.\n", mem, bytes); @@ -101,6 +106,14 @@ void bh_memory_destroy() memory_mode = MEMORY_MODE_UNKNOWN; } +int bh_memory_pool_size() +{ + if (memory_mode == MEMORY_MODE_POOL) + return global_pool_size; + else + return 1 * BH_GB; +} + void* bh_malloc_internal(unsigned int size) { if (memory_mode == MEMORY_MODE_UNKNOWN) { diff --git a/core/shared-lib/platform/linux/bh_thread.c b/core/shared-lib/platform/linux/bh_thread.c index 201c9b5e68..d2cdd087c8 100755 --- a/core/shared-lib/platform/linux/bh_thread.c +++ b/core/shared-lib/platform/linux/bh_thread.c @@ -75,7 +75,7 @@ static void *vm_thread_wrapper(void *arg) { thread_wrapper_arg * targ = arg; LOG_VERBOSE("THREAD CREATE 0x%08x\n", &targ); - targ->stack = (void *) ((unsigned int) (&arg) & ~0xfff); + targ->stack = (void *)((uintptr_t)(&arg) & ~0xfff); _vm_tls_put(1, targ); targ->start(targ->arg); bh_free(targ); From 177218332506d9183af6028ef2e88092d9554a49 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Tue, 11 Jun 2019 10:43:12 +0800 Subject: [PATCH 3/3] Add a new extension library: connection --- README.md | 27 +- core/app-mgr/app-manager/module_wasm_app.h | 6 +- core/iwasm/lib/app-libs/base/wasm_app.h | 1 + .../extension/connection/connection.c | 130 ++++ .../extension/connection/connection.h | 106 ++++ .../lib/native-interface/connection_api.h | 38 ++ .../lib/native-interface/native_interface.h | 12 +- .../extension/connection/connection.inl | 20 + .../extension/connection/connection_lib.h | 86 +++ .../extension/connection/connection_wrapper.c | 84 +++ .../extension/connection/linux/conn_tcp.c | 62 ++ .../extension/connection/linux/conn_tcp.h | 37 ++ .../extension/connection/linux/conn_uart.c | 110 ++++ .../extension/connection/linux/conn_uart.h | 37 ++ .../extension/connection/linux/conn_udp.c | 68 +++ .../extension/connection/linux/conn_udp.h | 37 ++ .../connection/linux/connection_mgr.c | 572 ++++++++++++++++++ .../connection/linux/connection_mgr.cmake | 24 + .../extension/connection/wasm_lib_conn.cmake | 23 + .../connection/zephyr/connection_lib_impl.c | 34 ++ core/shared-lib/include/config.h | 3 + .../littlevgl/vgl-wasm-runtime/CMakeLists.txt | 4 + .../vgl-wasm-runtime/src/ext_lib_export.c | 3 + .../src/platform/linux/iwasm_main.c | 7 + .../zephyr-build/CMakeLists.txt | 3 + samples/littlevgl/wasm-apps/Makefile_wasm_app | 17 +- samples/simple/CMakeLists.txt | 4 + samples/simple/README.md | 26 +- samples/simple/build.sh | 63 +- samples/simple/src/ext_lib_export.c | 2 + samples/simple/src/iwasm_main.c | 8 +- samples/simple/wasm-apps/connection.c | 93 +++ .../{event_publisher => }/event_publisher.c | 0 .../{event_subscriber => }/event_subscriber.c | 0 .../{request_handler => }/request_handler.c | 0 .../{request_sender => }/request_sender.c | 0 .../simple/wasm-apps/{sensor => }/sensor.c | 0 samples/simple/wasm-apps/{timer => }/timer.c | 0 38 files changed, 1677 insertions(+), 70 deletions(-) create mode 100644 core/iwasm/lib/app-libs/extension/connection/connection.c create mode 100644 core/iwasm/lib/app-libs/extension/connection/connection.h create mode 100644 core/iwasm/lib/native-interface/connection_api.h create mode 100644 core/iwasm/lib/native/extension/connection/connection.inl create mode 100644 core/iwasm/lib/native/extension/connection/connection_lib.h create mode 100644 core/iwasm/lib/native/extension/connection/connection_wrapper.c create mode 100644 core/iwasm/lib/native/extension/connection/linux/conn_tcp.c create mode 100644 core/iwasm/lib/native/extension/connection/linux/conn_tcp.h create mode 100644 core/iwasm/lib/native/extension/connection/linux/conn_uart.c create mode 100644 core/iwasm/lib/native/extension/connection/linux/conn_uart.h create mode 100644 core/iwasm/lib/native/extension/connection/linux/conn_udp.c create mode 100644 core/iwasm/lib/native/extension/connection/linux/conn_udp.h create mode 100644 core/iwasm/lib/native/extension/connection/linux/connection_mgr.c create mode 100644 core/iwasm/lib/native/extension/connection/linux/connection_mgr.cmake create mode 100644 core/iwasm/lib/native/extension/connection/wasm_lib_conn.cmake create mode 100644 core/iwasm/lib/native/extension/connection/zephyr/connection_lib_impl.c create mode 100644 samples/simple/wasm-apps/connection.c rename samples/simple/wasm-apps/{event_publisher => }/event_publisher.c (100%) rename samples/simple/wasm-apps/{event_subscriber => }/event_subscriber.c (100%) rename samples/simple/wasm-apps/{request_handler => }/request_handler.c (100%) rename samples/simple/wasm-apps/{request_sender => }/request_sender.c (100%) rename samples/simple/wasm-apps/{sensor => }/sensor.c (100%) rename samples/simple/wasm-apps/{timer => }/timer.c (100%) diff --git a/README.md b/README.md index fed5aa90a0..a687f6dec0 100644 --- a/README.md +++ b/README.md @@ -339,12 +339,35 @@ void api_timer_restart(user_timer_t timer, int interval); Currently we provide the sensor API's as one library extension sample. In the header file ```lib/app-libs/extension/sensor/sensor.h```, the API set is defined as below: ``` C sensor_t sensor_open(const char* name, int index, - void(*on_sensor_event)(sensor_t, attr_container_t *, void *), - void *user_data); + void(*on_sensor_event)(sensor_t, attr_container_t *, void *), + void *user_data); bool sensor_config(sensor_t sensor, int interval, int bit_cfg, int delay); bool sensor_config_with_attr_container(sensor_t sensor, attr_container_t *cfg); bool sensor_close(sensor_t sensor); ``` +We provide the connection API's as another sample. In the header file `lib/app-libs/extension/connection/connection.h.`, the API set is defined as below: +``` C +/* Connection event type */ +typedef enum { + /* Data is received */ + CONN_EVENT_TYPE_DATA = 1, + /* Connection is disconnected */ + CONN_EVENT_TYPE_DISCONNECT +} conn_event_type_t; + +typedef void (*on_connection_event_f)(connection_t *conn, + conn_event_type_t type, + const char *data, + uint32 len, + void *user_data); +connection_t *api_open_connection(const char *name, + attr_container_t *args, + on_connection_event_f on_event, + void *user_data); +void api_close_connection(connection_t *conn); +int api_send_on_connection(connection_t *conn, const char *data, uint32 len); +bool api_config_connection(connection_t *conn, attr_container_t *cfg); +``` The mechanism of exporting native API to WASM application ======================================================= diff --git a/core/app-mgr/app-manager/module_wasm_app.h b/core/app-mgr/app-manager/module_wasm_app.h index dbdf805270..e63a6d3c9f 100644 --- a/core/app-mgr/app-manager/module_wasm_app.h +++ b/core/app-mgr/app-manager/module_wasm_app.h @@ -39,8 +39,10 @@ extern "C" { #define SECTION_TYPE_DATA 11 enum { - WASM_Msg_Start = BASE_EVENT_MAX, TIMER_EVENT_WASM, SENSOR_EVENT_WASM, - + WASM_Msg_Start = BASE_EVENT_MAX, + TIMER_EVENT_WASM, + SENSOR_EVENT_WASM, + CONNECTION_EVENT_WASM, WASM_Msg_End = WASM_Msg_Start + 100 }; diff --git a/core/iwasm/lib/app-libs/base/wasm_app.h b/core/iwasm/lib/app-libs/base/wasm_app.h index 03c8460ba9..0aa223c65c 100644 --- a/core/iwasm/lib/app-libs/base/wasm_app.h +++ b/core/iwasm/lib/app-libs/base/wasm_app.h @@ -37,6 +37,7 @@ #include "attr_container.h" #include "request.h" #include "sensor.h" +#include "connection.h" #include "timer_wasm_app.h" #ifdef __cplusplus diff --git a/core/iwasm/lib/app-libs/extension/connection/connection.c b/core/iwasm/lib/app-libs/extension/connection/connection.c new file mode 100644 index 0000000000..1c7845d4b6 --- /dev/null +++ b/core/iwasm/lib/app-libs/extension/connection/connection.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "connection.h" +#include "native_interface.h" + +/* Raw connection structure */ +typedef struct _connection { + /* Next connection */ + struct _connection *next; + + /* Handle of the connection */ + uint32 handle; + + /* Callback function called when event on this connection occurs */ + on_connection_event_f on_event; + + /* User data */ + void *user_data; +} connection_t; + +/* Raw connections list */ +static connection_t *g_conns = NULL; + +connection_t *api_open_connection(const char *name, + attr_container_t *args, + on_connection_event_f on_event, + void *user_data) +{ + connection_t *conn; + char *args_buffer = (char *)args; + uint32 handle, args_len = attr_container_get_serialize_length(args); + + handle = wasm_open_connection((int32)name, (int32)args_buffer, args_len); + if (handle == -1) + return NULL; + + conn = (connection_t *)malloc(sizeof(*conn)); + if (conn == NULL) { + wasm_close_connection(handle); + return NULL; + } + + memset(conn, 0, sizeof(*conn)); + conn->handle = handle; + conn->on_event = on_event; + conn->user_data = user_data; + + if (g_conns != NULL) { + conn->next = g_conns; + g_conns = conn; + } else { + g_conns = conn; + } + + return conn; +} + +void api_close_connection(connection_t *c) +{ + connection_t *conn = g_conns, *prev = NULL; + + while (conn) { + if (conn == c) { + wasm_close_connection(c->handle); + if (prev != NULL) + prev->next = conn->next; + else + g_conns = conn->next; + free(conn); + return; + } else { + prev = conn; + conn = conn->next; + } + } +} + +int api_send_on_connection(connection_t *conn, const char *data, uint32 len) +{ + return wasm_send_on_connection(conn->handle, (int32)data, len); +} + +bool api_config_connection(connection_t *conn, attr_container_t *cfg) +{ + char *cfg_buffer = (char *)cfg; + uint32 cfg_len = attr_container_get_serialize_length(cfg); + + return wasm_config_connection(conn->handle, (int32)cfg_buffer, cfg_len); +} + +void on_connection_data(uint32 handle, char *buffer, uint32 len) +{ + connection_t *conn = g_conns; + + while (conn != NULL) { + if (conn->handle == handle) { + if (len == 0) { + conn->on_event(conn, + CONN_EVENT_TYPE_DISCONNECT, + NULL, + 0, + conn->user_data); + } else { + conn->on_event(conn, + CONN_EVENT_TYPE_DATA, + buffer, + len, + conn->user_data); + } + + return; + } + conn = conn->next; + } +} + diff --git a/core/iwasm/lib/app-libs/extension/connection/connection.h b/core/iwasm/lib/app-libs/extension/connection/connection.h new file mode 100644 index 0000000000..d87352a2bc --- /dev/null +++ b/core/iwasm/lib/app-libs/extension/connection/connection.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONNECTION_H_ +#define _CONNECTION_H_ + +#include "attr_container.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct _connection; +typedef struct _connection connection_t; + +/* Connection event type */ +typedef enum { + /* Data is received */ + CONN_EVENT_TYPE_DATA = 1, + /* Connection is disconnected */ + CONN_EVENT_TYPE_DISCONNECT +} conn_event_type_t; + +/* + * @typedef on_connection_event_f + * + * @param conn the connection that the event belongs to + * @param type event type + * @param data the data received for CONN_EVENT_TYPE_DATA event + * @param len length of the data in byte + * @param user_data user data + */ +typedef void (*on_connection_event_f)(connection_t *conn, + conn_event_type_t type, + const char *data, + uint32 len, + void *user_data); + +/* + ***************** + * Connection API's + ***************** + */ + +/* + * @brief Open a connection. + * + * @param name name of the connection, "TCP", "UDP" or "UART" + * @param args connection arguments, such as: ip:127.0.0.1, port:8888 + * @param on_event callback function called when event occurs + * @param user_data user data + * + * @return the connection or NULL means fail + */ +connection_t *api_open_connection(const char *name, + attr_container_t *args, + on_connection_event_f on_event, + void *user_data); + +/* + * @brief Close a connection. + * + * @param conn connection + */ +void api_close_connection(connection_t *conn); + +/* + * Send data to the connection in non-blocking manner which returns immediately + * + * @param conn the connection + * @param data data buffer to be sent + * @param len length of the data in byte + * + * @return actual length sent, or -1 if fail(maybe underlying buffer is full) + */ +int api_send_on_connection(connection_t *conn, const char *data, uint32 len); + +/* + * @brief Configure connection. + * + * @param conn the connection + * @param cfg configurations + * + * @return true if success, false otherwise + */ +bool api_config_connection(connection_t *conn, attr_container_t *cfg); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/iwasm/lib/native-interface/connection_api.h b/core/iwasm/lib/native-interface/connection_api.h new file mode 100644 index 0000000000..f55583bd9e --- /dev/null +++ b/core/iwasm/lib/native-interface/connection_api.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CONNECTION_API_H_ +#define CONNECTION_API_H_ +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +uint32 wasm_open_connection(int32 name_offset, int32 args_offset, uint32 len); + +void wasm_close_connection(uint32 handle); + +int wasm_send_on_connection(uint32 handle, int32 data_offset, uint32 len); + +bool wasm_config_connection(uint32 handle, int32 cfg_offset, uint32 len); + +#ifdef __cplusplus +} +#endif + + +#endif /* CONNECTION_API_H_ */ diff --git a/core/iwasm/lib/native-interface/native_interface.h b/core/iwasm/lib/native-interface/native_interface.h index a538330b78..a3c022d100 100644 --- a/core/iwasm/lib/native-interface/native_interface.h +++ b/core/iwasm/lib/native-interface/native_interface.h @@ -75,4 +75,14 @@ void wasm_timer_destory(timer_id_t timer_id); void wasm_timer_cancel(timer_id_t timer_id); void wasm_timer_restart(timer_id_t timer_id, int interval); uint32 wasm_get_sys_tick_ms(void); -#endif /* DEPS_SSG_MICRO_RUNTIME_WASM_POC_APP_LIBS_NATIVE_INTERFACE_NATIVE_INTERFACE_H_ */ + +/* + * *** connection interface *** + */ +uint32 wasm_open_connection(int32 name_offset, int32 args_offset, uint32 len); +void wasm_close_connection(uint32 handle); +int wasm_send_on_connection(uint32 handle, int32 data_offset, uint32 len); +bool wasm_config_connection(uint32 handle, int32 cfg_offset, uint32 len); + +#endif /* DEPS_SSG_MICRO_RUNTIME_WASM_PO +C_APP_LIBS_NATIVE_INTERFACE_NATIVE_INTERFACE_H_ */ diff --git a/core/iwasm/lib/native/extension/connection/connection.inl b/core/iwasm/lib/native/extension/connection/connection.inl new file mode 100644 index 0000000000..e736650931 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/connection.inl @@ -0,0 +1,20 @@ +/* +* Copyright (C) 2019 Intel Corporation. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +EXPORT_WASM_API(wasm_open_connection), +EXPORT_WASM_API(wasm_close_connection), +EXPORT_WASM_API(wasm_send_on_connection), +EXPORT_WASM_API(wasm_config_connection), diff --git a/core/iwasm/lib/native/extension/connection/connection_lib.h b/core/iwasm/lib/native/extension/connection/connection_lib.h new file mode 100644 index 0000000000..49d2e3970b --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/connection_lib.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CONNECTION_LIB_H_ +#define CONNECTION_LIB_H_ + +#include "attr_container.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ***************** + * This file defines connection library which should be implemented by different platforms + ***************** + */ + +/* + * @brief Open a connection. + * + * @param name name of the connection, "TCP", "UDP" or "UART" + * @param args connection arguments, such as: ip:127.0.0.1, port:8888 + * + * @return 0~0xFFFFFFFE means id of the connection, otherwise(-1) means fail + */ +typedef uint32 (*connection_open_f)(const char *name, attr_container_t *args); + +/* + * @brief Close a connection. + * + * @param handle of the connection + */ +typedef void (*connection_close_f)(uint32 handle); + +/* + * @brief Send data to the connection in non-blocking manner. + * + * @param handle of the connection + * @param data data buffer to be sent + * @param len length of the data in byte + * + * @return actual length sent, -1 if fail + */ +typedef int (*connection_send_f)(uint32 handle, const char *data, int len); + +/* + * @brief Configure connection. + * + * @param handle of the connection + * @param cfg configurations + * + * @return true if success, false otherwise + */ +typedef bool (*connection_config_f)(uint32 handle, attr_container_t *cfg); + +/* Raw connection interface for platform to implement */ +typedef struct _connection_interface { + connection_open_f _open; + connection_close_f _close; + connection_send_f _send; + connection_config_f _config; +} connection_interface_t; + +/* Platform must define this interface */ +extern connection_interface_t connection_impl; + +#ifdef __cplusplus +} +#endif + + +#endif /* CONNECTION_LIB_H_ */ diff --git a/core/iwasm/lib/native/extension/connection/connection_wrapper.c b/core/iwasm/lib/native/extension/connection/connection_wrapper.c new file mode 100644 index 0000000000..7bcf5860d1 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/connection_wrapper.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "connection_lib.h" +#include "wasm_export.h" +#include "native_interface.h" + +/* Note: + * + * This file is the consumer of connection lib which is implemented by different platforms + */ + + +uint32 wasm_open_connection(int32 name_offset, int32 args_offset, uint32 len) +{ + wasm_module_inst_t module_inst = get_module_inst(); + attr_container_t *args; + char *name, *args_buf; + + if (!validate_app_addr(name_offset, 1) || + !validate_app_addr(args_offset, len) || + !(name = addr_app_to_native(name_offset)) || + !(args_buf = addr_app_to_native(args_offset))) + return -1; + + args = (attr_container_t *)args_buf; + + if (connection_impl._open != NULL) + return connection_impl._open(name, args); + + return -1; +} + +void wasm_close_connection(uint32 handle) +{ + if (connection_impl._close != NULL) + connection_impl._close(handle); +} + +int wasm_send_on_connection(uint32 handle, int32 data_offset, uint32 len) +{ + wasm_module_inst_t module_inst = get_module_inst(); + char *data; + + if (!validate_app_addr(data_offset, len) || + !(data = addr_app_to_native(data_offset))) + return -1; + + if (connection_impl._send != NULL) + return connection_impl._send(handle, data, len); + + return -1; +} + +bool wasm_config_connection(uint32 handle, int32 cfg_offset, uint32 len) +{ + wasm_module_inst_t module_inst = get_module_inst(); + char *cfg_buf; + attr_container_t *cfg; + + if (!validate_app_addr(cfg_offset, len) || + !(cfg_buf = addr_app_to_native(cfg_offset))) + return false; + + cfg = (attr_container_t *)cfg_buf; + + if (connection_impl._config != NULL) + return connection_impl._config(handle, cfg); + + return false; +} diff --git a/core/iwasm/lib/native/extension/connection/linux/conn_tcp.c b/core/iwasm/lib/native/extension/connection/linux/conn_tcp.c new file mode 100644 index 0000000000..3a6bded260 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/linux/conn_tcp.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "conn_tcp.h" + +#include +#include +#include +#include +#include + +int tcp_open(char *address, uint16 port) +{ + int sock, ret; + struct sockaddr_in servaddr; + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = inet_addr(address); + servaddr.sin_port = htons(port); + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == -1) + return -1; + + ret = connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)); + if (ret == -1) { + close(sock); + return -1; + } + + /* Put the socket in non-blocking mode */ + if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) < 0) { + close(sock); + return -1; + } + + return sock; +} + +int tcp_send(int sock, const char *data, int size) +{ + return send(sock, data, size, 0); +} + +int tcp_recv(int sock, char *buffer, int buf_size) +{ + return recv(sock, buffer, buf_size, 0); +} diff --git a/core/iwasm/lib/native/extension/connection/linux/conn_tcp.h b/core/iwasm/lib/native/extension/connection/linux/conn_tcp.h new file mode 100644 index 0000000000..84caf2a131 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/linux/conn_tcp.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CONN_LINUX_TCP_H_ +#define CONN_LINUX_TCP_H_ + +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int tcp_open(char *address, uint16 port); + +int tcp_send(int sock, const char *data, int size); + +int tcp_recv(int sock, char *buffer, int buf_size); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/core/iwasm/lib/native/extension/connection/linux/conn_uart.c b/core/iwasm/lib/native/extension/connection/linux/conn_uart.c new file mode 100644 index 0000000000..6ca848b6ed --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/linux/conn_uart.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "conn_uart.h" + +#include +#include +#include + +static int parse_baudrate(int baud) +{ + switch (baud) { + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +int uart_open(char* device, int baudrate) +{ + int uart_fd; + struct termios uart_term; + + uart_fd = open(device, O_RDWR | O_NOCTTY); + + if (uart_fd <= 0) + return -1; + + memset(&uart_term, 0, sizeof(uart_term)); + uart_term.c_cflag = parse_baudrate(baudrate) | CS8 | CLOCAL | CREAD; + uart_term.c_iflag = IGNPAR; + uart_term.c_oflag = 0; + + /* set noncanonical mode */ + uart_term.c_lflag = 0; + uart_term.c_cc[VTIME] = 30; + uart_term.c_cc[VMIN] = 1; + tcflush(uart_fd, TCIFLUSH); + + if (tcsetattr(uart_fd, TCSANOW, &uart_term) != 0) { + close(uart_fd); + return -1; + } + + /* Put the fd in non-blocking mode */ + if (fcntl(uart_fd, F_SETFL, fcntl(uart_fd, F_GETFL) | O_NONBLOCK) < 0) { + close(uart_fd); + return -1; + } + + return uart_fd; +} + +int uart_send(int fd, const char *data, int size) +{ + return write(fd, data, size); +} + +int uart_recv(int fd, char *buffer, int buf_size) +{ + return read(fd, buffer, buf_size); +} diff --git a/core/iwasm/lib/native/extension/connection/linux/conn_uart.h b/core/iwasm/lib/native/extension/connection/linux/conn_uart.h new file mode 100644 index 0000000000..1e67811d64 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/linux/conn_uart.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CONN_LINUX_UART_H_ +#define CONN_LINUX_UART_H_ + +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int uart_open(char* device, int baudrate); + +int uart_send(int fd, const char *data, int size); + +int uart_recv(int fd, char *buffer, int buf_size); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/core/iwasm/lib/native/extension/connection/linux/conn_udp.c b/core/iwasm/lib/native/extension/connection/linux/conn_udp.c new file mode 100644 index 0000000000..d93c23f8ca --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/linux/conn_udp.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "conn_udp.h" + +#include +#include +#include +#include +#include + +int udp_open(uint16 port) +{ + int sock, ret; + struct sockaddr_in addr; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + ret = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); + if (ret == -1) + return -1; + + /* Put the socket in non-blocking mode */ + if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) < 0) { + close(sock); + return -1; + } + + return sock; +} + +int udp_send(int sock, struct sockaddr *dest, const char *data, int size) +{ + return sendto(sock, data, size, MSG_CONFIRM, dest, sizeof(*dest)); +} + +int udp_recv(int sock, char *buffer, int buf_size) +{ + struct sockaddr_in remaddr; + socklen_t addrlen = sizeof(remaddr); + + return recvfrom(sock, + buffer, + buf_size, + 0, + (struct sockaddr *)&remaddr, + &addrlen); +} diff --git a/core/iwasm/lib/native/extension/connection/linux/conn_udp.h b/core/iwasm/lib/native/extension/connection/linux/conn_udp.h new file mode 100644 index 0000000000..f3cbf4b199 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/linux/conn_udp.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CONN_LINUX_UDP_H_ +#define CONN_LINUX_UDP_H_ + +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int udp_open(uint16 port); + +int udp_send(int sock, struct sockaddr *dest, const char *data, int size); + +int udp_recv(int sock, char *buffer, int buf_size); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/core/iwasm/lib/native/extension/connection/linux/connection_mgr.c b/core/iwasm/lib/native/extension/connection/linux/connection_mgr.c new file mode 100644 index 0000000000..27c18cd775 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/linux/connection_mgr.c @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Note: + * This file implements the linux version connection library which is + * defined in connection_lib.h. + * It also provides a reference implementation of connections manager. + */ + +#include "connection_lib.h" +#include "bh_thread.h" +#include "app_manager_export.h" +#include "module_wasm_app.h" +#include "conn_tcp.h" +#include "conn_udp.h" +#include "conn_uart.h" +#include "bh_definition.h" + +#include +#include +#include +#include +#include + +#define MAX_EVENTS 10 +#define IO_BUF_SIZE 256 + +/* Connection type */ +typedef enum conn_type { + CONN_TYPE_TCP, + CONN_TYPE_UDP, + CONN_TYPE_UART, + CONN_TYPE_UNKNOWN +} conn_type_t; + +/* Sys connection */ +typedef struct sys_connection { + /* Next connection */ + struct sys_connection *next; + + /* Type */ + conn_type_t type; + + /* Handle to interact with wasm app */ + uint32 handle; + + /* Underlying connection ID, may be socket fd */ + int fd; + + /* Module id that the connection belongs to */ + uint32 module_id; + + /* Argument, such as dest addr for udp */ + void *arg; +} sys_connection_t; + +/* Epoll instance */ +static int epollfd; + +/* Connections list */ +static sys_connection_t *g_connections = NULL; + +/* Max handle */ +static uint32 g_handle_max = 0; + +/* Lock to protect g_connections and g_handle_max */ +static korp_mutex g_lock; + +/* Epoll events */ +static struct epoll_event epoll_events[MAX_EVENTS]; + +/* Buffer to receive data */ +static char io_buf[IO_BUF_SIZE]; + +static uint32 _conn_open(const char *name, attr_container_t *args); +static void _conn_close(uint32 handle); +static int _conn_send(uint32 handle, const char *data, int len); +static bool _conn_config(uint32 handle, attr_container_t *cfg); + +/* + * Platform implementation of connection library + */ +connection_interface_t connection_impl = { + ._open = _conn_open, + ._close = _conn_close, + ._send = _conn_send, + ._config = _conn_config +}; + +static void add_connection(sys_connection_t *conn) +{ + vm_mutex_lock(&g_lock); + + g_handle_max++; + if (g_handle_max == -1) + g_handle_max++; + conn->handle = g_handle_max; + + if (g_connections) { + conn->next = g_connections; + g_connections = conn; + } else { + g_connections = conn; + } + + vm_mutex_unlock(&g_lock); +} + +#define FREE_CONNECTION(conn) do { \ + if (conn->arg) \ + bh_free(conn->arg); \ + bh_free(conn); \ +} while (0) + +static int get_app_conns_num(uint32 module_id) +{ + sys_connection_t *conn; + int num = 0; + + vm_mutex_lock(&g_lock); + + conn = g_connections; + while (conn) { + if (conn->module_id == module_id) + num++; + conn = conn->next; + } + + vm_mutex_unlock(&g_lock); + + return num; +} + +static sys_connection_t *find_connection(uint32 handle, bool remove_found) +{ + sys_connection_t *conn, *prev = NULL; + + vm_mutex_lock(&g_lock); + + conn = g_connections; + while (conn) { + if (conn->handle == handle) { + if (remove_found) { + if (prev != NULL) { + prev->next = conn->next; + } else { + g_connections = conn->next; + } + } + vm_mutex_unlock(&g_lock); + return conn; + } else { + prev = conn; + conn = conn->next; + } + } + + vm_mutex_unlock(&g_lock); + + return NULL; +} + +static void cleanup_connections(uint32 module_id) +{ + sys_connection_t *conn, *prev = NULL; + + vm_mutex_lock(&g_lock); + + conn = g_connections; + while (conn) { + if (conn->module_id == module_id) { + epoll_ctl(epollfd, EPOLL_CTL_DEL, conn->fd, NULL); + close(conn->fd); + + if (prev != NULL) { + prev->next = conn->next; + FREE_CONNECTION(conn); + conn = prev->next; + } else { + g_connections = conn->next; + FREE_CONNECTION(conn); + conn = g_connections; + } + } else { + prev = conn; + conn = conn->next; + } + } + + vm_mutex_unlock(&g_lock); +} + +static conn_type_t get_conn_type(const char *name) +{ + if (strcmp(name, "TCP") == 0) + return CONN_TYPE_TCP; + if (strcmp(name, "UDP") == 0) + return CONN_TYPE_UDP; + if (strcmp(name, "UART") == 0) + return CONN_TYPE_UART; + + return CONN_TYPE_UNKNOWN; +} + +/* --- connection lib function --- */ +static uint32 _conn_open(const char *name, attr_container_t *args) +{ + int fd; + sys_connection_t *conn; + struct epoll_event ev; + uint32 module_id = app_manager_get_module_id(Module_WASM_App); + + if (get_app_conns_num(module_id) >= MAX_CONNECTION_PER_APP) + return -1; + + conn = (sys_connection_t *)bh_malloc(sizeof(*conn)); + if (conn == NULL) + return -1; + + memset(conn, 0, sizeof(*conn)); + conn->module_id = module_id; + conn->type = get_conn_type(name); + + /* Generate a handle and add to list */ + add_connection(conn); + + if (conn->type == CONN_TYPE_TCP) { + char *address; + uint16 port; + + /* Check and parse connection parameters */ + if (!attr_container_contain_key(args, "address") || + !attr_container_contain_key(args, "port")) + goto fail; + + address = attr_container_get_as_string(args, "address"); + port = attr_container_get_as_uint16(args, "port"); + + /* Connect to TCP server */ + if ((fd = tcp_open(address, port)) == -1) + goto fail; + + } else if (conn->type == CONN_TYPE_UDP) { + uint16 port; + + /* Check and parse connection parameters */ + if (!attr_container_contain_key(args, "bind port")) + goto fail; + port = attr_container_get_as_uint16(args, "bind port"); + + /* Bind port */ + if ((fd = udp_open(port)) == -1) + goto fail; + + } else if (conn->type == CONN_TYPE_UART) { + char *device; + int baud; + + /* Check and parse connection parameters */ + if (!attr_container_contain_key(args, "device") || + !attr_container_contain_key(args, "baudrate")) + goto fail; + device = attr_container_get_as_string(args, "device"); + baud = attr_container_get_as_int(args, "baudrate"); + + /* Open device */ + if ((fd = uart_open(device, baud)) == -1) + goto fail; + + } + + conn->fd = fd; + + /* Set current connection as event data */ + ev.events = EPOLLIN; + ev.data.ptr = conn; + + /* Monitor incoming data */ + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { + close(fd); + goto fail; + } + + return conn->handle; + +fail: + find_connection(conn->handle, true); + bh_free(conn); + return -1; +} + +/* --- connection lib function --- */ +static void _conn_close(uint32 handle) +{ + sys_connection_t *conn = find_connection(handle, true); + + if (conn != NULL) { + epoll_ctl(epollfd, EPOLL_CTL_DEL, conn->fd, NULL); + close(conn->fd); + FREE_CONNECTION(conn); + } +} + +/* --- connection lib function --- */ +static int _conn_send(uint32 handle, const char *data, int len) +{ + sys_connection_t *conn = find_connection(handle, false); + + if (conn == NULL) + return -1; + + if (conn->type == CONN_TYPE_TCP) + return tcp_send(conn->fd, data, len); + + if (conn->type == CONN_TYPE_UDP) { + struct sockaddr *addr = (struct sockaddr *)conn->arg; + return udp_send(conn->fd, addr, data, len); + } + + if (conn->type == CONN_TYPE_UART) + return uart_send(conn->fd, data, len); + + return -1; +} + +/* --- connection lib function --- */ +static bool _conn_config(uint32 handle, attr_container_t *cfg) +{ + sys_connection_t *conn = find_connection(handle, false); + + if (conn == NULL) + return false; + + if (conn->type == CONN_TYPE_UDP) { + char *address; + uint16_t port; + struct sockaddr_in *addr; + + /* Parse remote address/port */ + if (!attr_container_contain_key(cfg, "address") || + !attr_container_contain_key(cfg, "port")) + return false; + address = attr_container_get_as_string(cfg, "address"); + port = attr_container_get_as_uint16(cfg, "port"); + + if (conn->arg == NULL) { + addr = (struct sockaddr_in *)bh_malloc(sizeof(*addr)); + if (addr == NULL) + return false; + + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = inet_addr(address); + addr->sin_port = htons(port); + + /* Set remote address as connection arg */ + conn->arg = addr; + } else { + addr = (struct sockaddr_in *)conn->arg; + addr->sin_addr.s_addr = inet_addr(address); + addr->sin_port = htons(port); + } + + return true; + } + + return false; +} + +/* --- connection manager reference implementation ---*/ + +typedef struct connection_event { + uint32 handle; + char *data; + uint32 len; +} connection_event_t; + +static void connection_event_cleaner(connection_event_t *conn_event) +{ + if (conn_event->data != NULL) + bh_free(conn_event->data); + bh_free(conn_event); +} + +static void post_msg_to_module(sys_connection_t *conn, + char *data, + uint32 len) +{ + module_data *module = module_data_list_lookup_id(conn->module_id); + char *data_copy = NULL; + connection_event_t *conn_data_event; + bh_message_t msg; + + if (module == NULL) + return; + + conn_data_event = (connection_event_t *)bh_malloc(sizeof(*conn_data_event)); + if (conn_data_event == NULL) + return; + + if (len > 0) { + data_copy = (char *)bh_malloc(len); + if (data_copy == NULL) { + bh_free(conn_data_event); + return; + } + memcpy(data_copy, data, len); + } + + memset(conn_data_event, 0, sizeof(*conn_data_event)); + conn_data_event->handle = conn->handle; + conn_data_event->data = data_copy; + conn_data_event->len = len; + + msg = bh_new_msg(CONNECTION_EVENT_WASM, + conn_data_event, + sizeof(*conn_data_event), + connection_event_cleaner); + if (!msg) { + connection_event_cleaner(conn_data_event); + return; + } + + bh_post_msg2(module->queue, msg); +} + +static void* polling_thread_routine (void *arg) +{ + while (true) { + int i, n; + + n = epoll_wait(epollfd, epoll_events, MAX_EVENTS, -1); + + if (n == -1 && errno != EINTR) + continue; + + for (i = 0; i < n; i++) { + sys_connection_t *conn + = (sys_connection_t *)epoll_events[i].data.ptr; + + if (conn->type == CONN_TYPE_TCP) { + int count = tcp_recv(conn->fd, io_buf, IO_BUF_SIZE); + if (count <= 0) { + /* Connection is closed by peer */ + post_msg_to_module(conn, NULL, 0); + _conn_close(conn->handle); + } else { + /* Data is received */ + post_msg_to_module(conn, io_buf, count); + } + } else if (conn->type == CONN_TYPE_UDP) { + int count = udp_recv(conn->fd, io_buf, IO_BUF_SIZE); + if (count > 0) + post_msg_to_module(conn, io_buf, count); + } else if (conn->type == CONN_TYPE_UART) { + int count = uart_recv(conn->fd, io_buf, IO_BUF_SIZE); + if (count > 0) + post_msg_to_module(conn, io_buf, count); + } + } + } + + return NULL; +} + +void app_mgr_connection_event_callback(module_data *m_data, bh_message_t msg) +{ + uint32 argv[3]; + wasm_function_inst_t func_on_conn_data; + bh_assert(CONNECTION_EVENT_WASM == bh_message_type(msg)); + wasm_data *wasm_app_data = (wasm_data*) m_data->internal_data; + wasm_module_inst_t inst = wasm_app_data->wasm_module_inst; + connection_event_t *conn_event + = (connection_event_t *)bh_message_payload(msg); + int32 data_offset; + + if (conn_event == NULL) + return; + + func_on_conn_data = wasm_runtime_lookup_function(inst, "_on_connection_data", + "(i32i32i32)"); + if (!func_on_conn_data) { + printf("Cannot find function _on_connection_data\n"); + return; + } + + /* 0 len means connection closed */ + if (conn_event->len == 0) { + argv[0] = conn_event->handle; + argv[1] = 0; + argv[2] = 0; + if (!wasm_runtime_call_wasm(inst, NULL, func_on_conn_data, 3, argv)) { + printf(":Got exception running wasm code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + return; + } + } else { + data_offset = wasm_runtime_module_dup_data(inst, + conn_event->data, + conn_event->len); + if (data_offset == 0) { + printf("Got exception running wasm code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + return; + } + + argv[0] = conn_event->handle; + argv[1] = (uint32) data_offset; + argv[2] = conn_event->len; + if (!wasm_runtime_call_wasm(inst, NULL, func_on_conn_data, 3, argv)) { + printf(":Got exception running wasm code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + wasm_runtime_module_free(inst, data_offset); + return; + } + wasm_runtime_module_free(inst, data_offset); + } +} + +bool init_connection_framework() +{ + korp_thread tid; + + epollfd = epoll_create(MAX_EVENTS); + if (epollfd == -1) + return false; + + if (vm_mutex_init(&g_lock) != BH_SUCCESS) { + close(epollfd); + return false; + } + + if (!wasm_register_cleanup_callback(cleanup_connections)) { + goto fail; + } + + if (!wasm_register_msg_callback(CONNECTION_EVENT_WASM, + app_mgr_connection_event_callback)) { + goto fail; + } + + if (vm_thread_create(&tid, + polling_thread_routine, + NULL, + BH_APPLET_PRESERVED_STACK_SIZE) != BH_SUCCESS) { + goto fail; + } + + return true; + +fail: + vm_mutex_destroy(&g_lock); + close(epollfd); + return false; +} diff --git a/core/iwasm/lib/native/extension/connection/linux/connection_mgr.cmake b/core/iwasm/lib/native/extension/connection/linux/connection_mgr.cmake new file mode 100644 index 0000000000..72ab4554d4 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/linux/connection_mgr.cmake @@ -0,0 +1,24 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set (WASM_LIB_CONN_MGR_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${WASM_LIB_CONN_MGR_DIR}) + + +file (GLOB_RECURSE source_all ${WASM_LIB_CONN_MGR_DIR}/*.c) + +set (WASM_LIB_CONN_MGR_SOURCE ${source_all}) + + diff --git a/core/iwasm/lib/native/extension/connection/wasm_lib_conn.cmake b/core/iwasm/lib/native/extension/connection/wasm_lib_conn.cmake new file mode 100644 index 0000000000..2018706e80 --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/wasm_lib_conn.cmake @@ -0,0 +1,23 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set (WASM_LIB_CONN_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${WASM_LIB_CONN_DIR}) + + +file (GLOB source_all ${WASM_LIB_CONN_DIR}/*.c) + +set (WASM_LIB_CONN_SOURCE ${source_all}) + diff --git a/core/iwasm/lib/native/extension/connection/zephyr/connection_lib_impl.c b/core/iwasm/lib/native/extension/connection/zephyr/connection_lib_impl.c new file mode 100644 index 0000000000..379437076f --- /dev/null +++ b/core/iwasm/lib/native/extension/connection/zephyr/connection_lib_impl.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Note: + * This file implements the linux version connection library which is + * defined in connection_lib.h. + * It also provides a reference impl of connections manager. + */ + +#include "connection_lib.h" + +/* + * Platform implementation of connection library + */ +connection_interface_t connection_impl = { + ._open = NULL, + ._close = NULL, + ._send = NULL, + ._config = NULL +}; diff --git a/core/shared-lib/include/config.h b/core/shared-lib/include/config.h index 0c270cbc70..14f379c7e4 100644 --- a/core/shared-lib/include/config.h +++ b/core/shared-lib/include/config.h @@ -63,6 +63,9 @@ /* Max timer number in one app */ #define MAX_TIMERS_PER_APP 30 +/* Max connection number in one app */ +#define MAX_CONNECTION_PER_APP 20 + /* Max resource registration number in one app */ #define RESOURCE_REGISTRATION_NUM_MAX 16 diff --git a/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt b/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt index 719f866b40..9f2f29a7d0 100644 --- a/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt +++ b/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt @@ -57,6 +57,8 @@ include (${WASM_DIR}/runtime/vmcore-wasm/vmcore.cmake) include (${WASM_DIR}/lib/native/base/wasm_lib_base.cmake) include (${WASM_DIR}/lib/native/libc/wasm_libc.cmake) include (${WASM_DIR}/lib/native/extension/sensor/wasm_lib_sensor.cmake) +include (${WASM_DIR}/lib/native/extension/connection/wasm_lib_conn.cmake) +include (${WASM_DIR}/lib/native/extension/connection/${TARGET_PLATFORM}/connection_mgr.cmake) include (${WASM_DIR}/lib/native-interface/native_interface.cmake) include (${APP_MGR_DIR}/app-manager/app_mgr.cmake) include (${APP_MGR_DIR}/app-mgr-shared/app_mgr_shared.cmake) @@ -81,6 +83,8 @@ add_library (vmlib ${WASM_LIB_BASE_SOURCE} ${WASM_LIB_EXT_SOURCE} ${WASM_LIB_SENSOR_SOURCE} + ${WASM_LIB_CONN_SOURCE} + ${WASM_LIB_CONN_MGR_SOURCE} ${PLATFORM_SHARED_SOURCE} ${UTILS_SHARED_SOURCE} ${MEM_ALLOC_SHARED_SOURCE} diff --git a/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c b/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c index 8927493a8f..3897b3b0b4 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c @@ -1,8 +1,11 @@ #include "lib_export.h" #include "native_interface.h" +#include "connection_api.h" #include "display_indev.h" + static NativeSymbol extended_native_symbol_defs[] = { #include "runtime_sensor.inl" +#include "connection.inl" EXPORT_WASM_API(display_init), EXPORT_WASM_API(display_input_read), EXPORT_WASM_API(display_flush), diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c index c5d23b0579..15d94d3033 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c @@ -46,6 +46,7 @@ static int baudrate = B115200; extern void * thread_timer_check(void *); extern void init_sensor_framework(); extern int aee_host_msg_callback(void *msg, uint16_t msg_len); +extern bool init_connection_framework(); #ifndef CONNECTION_UART int listenfd = -1; @@ -441,6 +442,12 @@ int iwasm_main(int argc, char *argv[]) if (vm_thread_sys_init() != 0) { goto fail1; } + + if (!init_connection_framework()) { + vm_thread_sys_destroy(); + goto fail1; + } + extern void display_SDL_init(); display_SDL_init(); diff --git a/samples/littlevgl/vgl-wasm-runtime/zephyr-build/CMakeLists.txt b/samples/littlevgl/vgl-wasm-runtime/zephyr-build/CMakeLists.txt index bb5948ed9c..bd7c016989 100644 --- a/samples/littlevgl/vgl-wasm-runtime/zephyr-build/CMakeLists.txt +++ b/samples/littlevgl/vgl-wasm-runtime/zephyr-build/CMakeLists.txt @@ -38,6 +38,7 @@ target_include_directories(app PRIVATE ${IWASM_ROOT}/runtime/include ${IWASM_ROOT}/lib/native/base ${IWASM_ROOT}/lib/native/libc ${IWASM_ROOT}/lib/native/extension/sensor + ${IWASM_ROOT}/lib/native/extension/connection ${IWASM_ROOT}/lib/native-interface ${APP_MGR_ROOT}/app-manager ${APP_MGR_ROOT}/app-mgr-shared @@ -69,6 +70,8 @@ set (IWASM_SRCS ${IWASM_ROOT}/runtime/platform/zephyr/wasm_math.c ${IWASM_ROOT}/lib/native/base/timer_wrapper.c ${IWASM_ROOT}/lib/native/libc/libc_wrapper.c ${IWASM_ROOT}/lib/native/extension/sensor/runtime_sensor.c + ${IWASM_ROOT}/lib/native/extension/connection/connection_wrapper.c + ${IWASM_ROOT}/lib/native/extension/connection/zephyr/connection_lib_impl.c ${IWASM_ROOT}/lib/native-interface/attr_container.c ${IWASM_ROOT}/lib/native-interface/restful_utils.c ${APP_MGR_ROOT}/app-manager/app_manager.c diff --git a/samples/littlevgl/wasm-apps/Makefile_wasm_app b/samples/littlevgl/wasm-apps/Makefile_wasm_app index dcf7f17243..03671e1d44 100644 --- a/samples/littlevgl/wasm-apps/Makefile_wasm_app +++ b/samples/littlevgl/wasm-apps/Makefile_wasm_app @@ -14,7 +14,17 @@ CC = emcc LVGL_DIR = ${shell pwd} -CFLAGS += -O3 -DLV_CONF_INCLUDE_SIMPLE=1 -I$(LVGL_DIR)/ -I$(LVGL_DIR)/lvgl/ -I$(LVGL_DIR)/lv_drivers/ -I$(LVGL_DIR)/src/ -I../../../core/iwasm/lib/app-libs/base/ -I../../../core/iwasm/lib/native-interface/ -I../../../core/iwasm/lib/app-libs/extension/sensor +IWASM_DIR=../../../core/iwasm +CFLAGS += -O3 \ + -DLV_CONF_INCLUDE_SIMPLE=1 \ + -I$(LVGL_DIR)/ \ + -I$(LVGL_DIR)/lvgl/ \ + -I$(LVGL_DIR)/lv_drivers/ \ + -I$(LVGL_DIR)/src/ \ + -I$(IWASM_DIR)/lib/app-libs/base/ \ + -I$(IWASM_DIR)/lib/native-interface/ \ + -I$(IWASM_DIR)/lib/app-libs/extension/sensor \ + -I$(IWASM_DIR)/lib/app-libs/extension/connection SRCS += lvgl/lv_draw/lv_draw_line.c lvgl/lv_draw/lv_draw_rbasic.c SRCS += lvgl/lv_draw/lv_draw_img.c lvgl/lv_draw/lv_draw_arc.c @@ -46,10 +56,11 @@ SRCS += lvgl/lv_core/lv_group.c lvgl/lv_core/lv_style.c lvgl/lv_core/lv_indev.c SRCS += lvgl/lv_core/lv_vdb.c lvgl/lv_core/lv_obj.c lvgl/lv_core/lv_refr.c SRCS += $(LVGL_DIR)/src/main.c -SRCS += ../../../core/iwasm/lib/app-libs/base/timer.c +# For app size consideration, not all but necessary app libs are included +SRCS += $(IWASM_DIR)/lib/app-libs/base/timer.c all: @$(CC) $(CFLAGS) $(SRCS) \ -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ -s TOTAL_MEMORY=65536 -s TOTAL_STACK=2048\ - -s "EXPORTED_FUNCTIONS=['_on_init', '_on_request', '_on_sensor_event', '_on_timer_callback']" \ + -s "EXPORTED_FUNCTIONS=['_on_init', '_on_timer_callback']" \ -o ui_app.wasm diff --git a/samples/simple/CMakeLists.txt b/samples/simple/CMakeLists.txt index 01fade4447..53fa768ea1 100644 --- a/samples/simple/CMakeLists.txt +++ b/samples/simple/CMakeLists.txt @@ -57,6 +57,8 @@ include (${WASM_DIR}/runtime/vmcore-wasm/vmcore.cmake) include (${WASM_DIR}/lib/native/base/wasm_lib_base.cmake) include (${WASM_DIR}/lib/native/libc/wasm_libc.cmake) include (${WASM_DIR}/lib/native/extension/sensor/wasm_lib_sensor.cmake) +include (${WASM_DIR}/lib/native/extension/connection/wasm_lib_conn.cmake) +include (${WASM_DIR}/lib/native/extension/connection/${TARGET_PLATFORM}/connection_mgr.cmake) include (${WASM_DIR}/lib/native-interface/native_interface.cmake) include (${APP_MGR_DIR}/app-manager/app_mgr.cmake) include (${APP_MGR_DIR}/app-mgr-shared/app_mgr_shared.cmake) @@ -83,6 +85,8 @@ add_library (vmlib ${WASM_LIB_BASE_SOURCE} ${WASM_LIB_EXT_SOURCE} ${WASM_LIB_SENSOR_SOURCE} + ${WASM_LIB_CONN_SOURCE} + ${WASM_LIB_CONN_MGR_SOURCE} ${PLATFORM_SHARED_SOURCE} ${UTILS_SHARED_SOURCE} ${MEM_ALLOC_SHARED_SOURCE} diff --git a/samples/simple/README.md b/samples/simple/README.md index b17dd9eb8e..aca5a50c80 100644 --- a/samples/simple/README.md +++ b/samples/simple/README.md @@ -16,18 +16,13 @@ simple/ │   ├── iwasm_main.c │   └── main.c └── wasm-apps - ├── event_publisher - │   └── event_publisher.c - ├── event_subscriber - │   └── event_subscriber.c - ├── request_handler - │   └── request_handler.c - ├── request_sender - │   └── request_sender.c - ├── sensor - │   └── sensor.c - └── timer -    └── timer.c + ├── connection.c + ├── event_publisher.c + ├── event_subscriber.c + ├── request_handler.c + ├── request_sender.c + ├── sensor.c + └── timer.c ``` - build.sh
@@ -75,18 +70,19 @@ Execute the build.sh script then all binaries including wasm application files w Out directory structure ------------------------------ - ``` +``` out/ ├── host_tool ├── simple └── wasm-apps + ├── connection.wasm ├── event_publisher.wasm ├── event_subscriber.wasm ├── request_handler.wasm ├── request_sender.wasm ├── sensor.wasm └── timer.wasm - ``` +``` - host_tool: A small testing tool to interact with WAMR. See the usage of this tool by executing "./host_tool -h". @@ -100,6 +96,8 @@ out/ - wasm-apps: Sample wasm applications that demonstrate all APIs of the WAMR programming model. The source codes are in the wasm-apps directory under the root of this project. + + connection.wasm
+ This application shows the connection programming model. It connects to a TCP server on 127.0.0.1:7777 and periodically sends message to it. + event_publisher.wasm
This application shows the sub/pub programming model. The pub application publishes the event "alert/overheat" by calling api_publish_event() API. The subscriber could be host_tool or other wasm application. + event_subscriber.wasm
diff --git a/samples/simple/build.sh b/samples/simple/build.sh index 1d8b8e1b16..453f1271f4 100755 --- a/samples/simple/build.sh +++ b/samples/simple/build.sh @@ -8,7 +8,7 @@ BUILD_DIR=${PWD}/build IWASM_ROOT=${PWD}/../../core/iwasm APP_LIBS=${IWASM_ROOT}/lib/app-libs NATIVE_LIBS=${IWASM_ROOT}/lib/native-interface -APP_LIB_SRC="${APP_LIBS}/base/*.c ${APP_LIBS}/extension/sensor/*.c ${NATIVE_LIBS}/*.c" +APP_LIB_SRC="${APP_LIBS}/base/*.c ${APP_LIBS}/extension/sensor/*.c ${APP_LIBS}/extension/connection/*.c ${NATIVE_LIBS}/*.c" WASM_APPS=${PWD}/wasm-apps rm -rf ${OUT_DIR} @@ -49,54 +49,23 @@ echo "#####################build host-tool success" echo "#####################build wasm apps" -cd ${CURR_DIR} - -APP_SRC="${WASM_APPS}/timer/timer.c ${APP_LIB_SRC}" -emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ - -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ - -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ - -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ - '_on_sensor_event', '_on_timer_callback']" \ - -o ${OUT_DIR}/wasm-apps/timer.wasm ${APP_SRC} - -APP_SRC="${WASM_APPS}/request_handler/request_handler.c ${APP_LIB_SRC}" -emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ - -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ - -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ - -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ - '_on_sensor_event', '_on_timer_callback']" \ - -o ${OUT_DIR}/wasm-apps/request_handler.wasm ${APP_SRC} - -APP_SRC="${WASM_APPS}/request_sender/request_sender.c ${APP_LIB_SRC}" -emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ - -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ - -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ - -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ - '_on_sensor_event', '_on_timer_callback']" \ - -o ${OUT_DIR}/wasm-apps/request_sender.wasm ${APP_SRC} - -APP_SRC="${WASM_APPS}/event_publisher/event_publisher.c ${APP_LIB_SRC}" -emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ - -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ - -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ - -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ - '_on_sensor_event', '_on_timer_callback']" \ - -o ${OUT_DIR}/wasm-apps/event_publisher.wasm ${APP_SRC} +cd ${WASM_APPS} -APP_SRC="${WASM_APPS}/event_subscriber/event_subscriber.c ${APP_LIB_SRC}" +for i in `ls *.c` +do +APP_SRC="$i ${APP_LIB_SRC}" +OUT_FILE=${i%.*}.wasm emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ + -I${APP_LIBS}/extension/connection \ -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ - '_on_sensor_event', '_on_timer_callback']" \ - -o ${OUT_DIR}/wasm-apps/event_subscriber.wasm ${APP_SRC} - -APP_SRC="${WASM_APPS}/sensor/sensor.c ${APP_LIB_SRC}" -emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ - -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ - -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ - -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ - '_on_sensor_event', '_on_timer_callback']" \ - -o ${OUT_DIR}/wasm-apps/sensor.wasm ${APP_SRC} - -echo "#####################build wasm apps success" + '_on_sensor_event', '_on_timer_callback', '_on_connection_data']" \ + -o ${OUT_DIR}/wasm-apps/${OUT_FILE} ${APP_SRC} +if [ -f ${OUT_DIR}/wasm-apps/${OUT_FILE} ]; then + echo "build ${OUT_FILE} success" +else + echo "build ${OUT_FILE} fail" +fi +done +echo "#####################build wasm apps done" diff --git a/samples/simple/src/ext_lib_export.c b/samples/simple/src/ext_lib_export.c index 89e572005d..24782b5e87 100644 --- a/samples/simple/src/ext_lib_export.c +++ b/samples/simple/src/ext_lib_export.c @@ -1,8 +1,10 @@ #include "lib_export.h" #include "sensor_api.h" +#include "connection_api.h" static NativeSymbol extended_native_symbol_defs[] = { #include "runtime_sensor.inl" +#include "connection.inl" }; #include "ext_lib_export.h" diff --git a/samples/simple/src/iwasm_main.c b/samples/simple/src/iwasm_main.c index d70b7e4d3c..141aa51403 100644 --- a/samples/simple/src/iwasm_main.c +++ b/samples/simple/src/iwasm_main.c @@ -46,6 +46,7 @@ static int baudrate = B115200; extern void * thread_timer_check(void *); extern void init_sensor_framework(); extern int aee_host_msg_callback(void *msg, uint16_t msg_len); +extern bool init_connection_framework(); #ifndef CONNECTION_UART int listenfd = -1; @@ -213,7 +214,7 @@ void* func_server_mode(void* arg) sockfd = -1; pthread_mutex_unlock(&sock_lock); - sleep(2); + sleep(1); break; } @@ -442,6 +443,11 @@ int iwasm_main(int argc, char *argv[]) goto fail1; } + if (!init_connection_framework()) { + vm_thread_sys_destroy(); + goto fail1; + } + init_sensor_framework(); // timer manager diff --git a/samples/simple/wasm-apps/connection.c b/samples/simple/wasm-apps/connection.c new file mode 100644 index 0000000000..89aed5170e --- /dev/null +++ b/samples/simple/wasm-apps/connection.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm_app.h" + +/* User global variable */ +static int num = 0; +static user_timer_t g_timer; +static connection_t *g_conn = NULL; + +void on_data1(connection_t *conn, + conn_event_type_t type, + const char *data, + uint32 len, + void *user_data) +{ + if (type == CONN_EVENT_TYPE_DATA) { + char message[64] = {0}; + memcpy(message, data, len); + printf("Client got a message from server -> %s\n", message); + } else if (type == CONN_EVENT_TYPE_DISCONNECT) { + printf("connection is close by server!\n"); + } else { + printf("error: got unknown event type!!!\n"); + } +} + +/* Timer callback */ +void timer1_update(user_timer_t timer) +{ + char message[64] = {0}; + /* Reply to server */ + snprintf(message, sizeof(message), "Hello %d", num++); + api_send_on_connection(g_conn, message, strlen(message)); +} + +void my_close_handler(request_t * request) +{ + response_t response[1]; + + if (g_conn != NULL) { + api_timer_cancel(g_timer); + api_close_connection(g_conn); + } + + make_response_for_request(request, response); + set_response(response, DELETED_2_02, 0, NULL, 0); + api_response_send(response); +} + +void on_init() +{ + user_timer_t timer; + attr_container_t *args; + char *str = "this is client!"; + + api_register_resource_handler("/close", my_close_handler); + + args = attr_container_create(""); + attr_container_set_string(&args, "address", "127.0.0.1"); + attr_container_set_uint16(&args, "port", 7777); + + g_conn = api_open_connection("TCP", args, on_data1, NULL); + if (g_conn == NULL) { + printf("connect to server fail!\n"); + return; + } + + printf("connect to server success! handle: %p\n", g_conn); + + /* set up a timer */ + timer = api_timer_create(1000, true, false, timer1_update); + api_timer_restart(timer, 1000); +} + +void on_destroy() +{ + /* real destroy work including killing timer and closing sensor is + accomplished in wasm app library version of on_destroy() */ +} diff --git a/samples/simple/wasm-apps/event_publisher/event_publisher.c b/samples/simple/wasm-apps/event_publisher.c similarity index 100% rename from samples/simple/wasm-apps/event_publisher/event_publisher.c rename to samples/simple/wasm-apps/event_publisher.c diff --git a/samples/simple/wasm-apps/event_subscriber/event_subscriber.c b/samples/simple/wasm-apps/event_subscriber.c similarity index 100% rename from samples/simple/wasm-apps/event_subscriber/event_subscriber.c rename to samples/simple/wasm-apps/event_subscriber.c diff --git a/samples/simple/wasm-apps/request_handler/request_handler.c b/samples/simple/wasm-apps/request_handler.c similarity index 100% rename from samples/simple/wasm-apps/request_handler/request_handler.c rename to samples/simple/wasm-apps/request_handler.c diff --git a/samples/simple/wasm-apps/request_sender/request_sender.c b/samples/simple/wasm-apps/request_sender.c similarity index 100% rename from samples/simple/wasm-apps/request_sender/request_sender.c rename to samples/simple/wasm-apps/request_sender.c diff --git a/samples/simple/wasm-apps/sensor/sensor.c b/samples/simple/wasm-apps/sensor.c similarity index 100% rename from samples/simple/wasm-apps/sensor/sensor.c rename to samples/simple/wasm-apps/sensor.c diff --git a/samples/simple/wasm-apps/timer/timer.c b/samples/simple/wasm-apps/timer.c similarity index 100% rename from samples/simple/wasm-apps/timer/timer.c rename to samples/simple/wasm-apps/timer.c