Skip to content

Commit 77c71e5

Browse files
authored
Add wasm-c-api nested function calls sample (#652)
And enable to copy back the return value of wasm main function when calling wasm_application_execute_main, add license headers in wasm-c-api samples, fix several issues reported by klocwork.
1 parent 1a4aa5a commit 77c71e5

File tree

15 files changed

+357
-9
lines changed

15 files changed

+357
-9
lines changed

core/iwasm/common/wasm_application.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
182182

183183
ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func,
184184
argc1, argv1);
185+
if (ret && func_type->result_count > 0 && argc > 0 && argv)
186+
/* copy the return value */
187+
*(int*)argv = (int)argv1[0];
188+
185189
if (argv_buf_offset)
186190
wasm_runtime_module_free(module_inst, argv_buf_offset);
187191
return ret;
@@ -669,4 +673,4 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
669673
bh_assert(exception);
670674
os_printf("%s\n", exception);
671675
return false;
672-
}
676+
}

core/iwasm/include/wasm_export.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,9 @@ wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env,
495495
*
496496
* @param module_inst the WASM module instance
497497
* @param argc the number of arguments
498-
* @param argv the arguments array
498+
* @param argv the arguments array, if the main function has return value,
499+
* *(int*)argv stores the return value of the called main function after
500+
* this function returns.
499501
*
500502
* @return true if the main function is called, false otherwise and exception
501503
* will be thrown, the caller can call wasm_runtime_get_exception to get

samples/spawn-thread/src/main.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ void *thread(void* arg)
2626
func = wasm_runtime_lookup_function(module_inst, "sum", NULL);
2727
if (!func) {
2828
printf("failed to lookup function sum");
29+
return NULL;
2930
}
3031
argv[0] = thread_arg->start;
3132
argv[1] = thread_arg->length;
@@ -49,6 +50,7 @@ void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg)
4950
func = wasm_runtime_lookup_function(module_inst, "sum", NULL);
5051
if (!func) {
5152
printf("failed to lookup function sum");
53+
return NULL;
5254
}
5355
argv[0] = thread_arg->start;
5456
argv[1] = thread_arg->length;
@@ -66,7 +68,7 @@ int main(int argc, char *argv[])
6668
{
6769
char *wasm_file = "wasm-apps/test.wasm";
6870
uint8 *wasm_file_buf = NULL;
69-
uint32 wasm_file_size, wasm_argv[2], i;
71+
uint32 wasm_file_size, wasm_argv[2], i, threads_created;
7072
uint32 stack_size = 16 * 1024, heap_size = 16 * 1024;
7173
wasm_module_t wasm_module = NULL;
7274
wasm_module_inst_t wasm_module_inst = NULL;
@@ -123,6 +125,7 @@ int main(int argc, char *argv[])
123125
func = wasm_runtime_lookup_function(wasm_module_inst, "sum", NULL);
124126
if (!func) {
125127
printf("failed to lookup function sum");
128+
goto fail5;
126129
}
127130
wasm_argv[0] = 0;
128131
wasm_argv[1] = THREAD_NUM * 10;
@@ -159,17 +162,20 @@ int main(int argc, char *argv[])
159162

160163
if (0 != pthread_create(&tid[i], NULL, thread, &thread_arg[i])) {
161164
printf("failed to create thread.\n");
165+
wasm_runtime_destroy_spawned_exec_env(new_exec_env);
162166
break;
163167
}
164168
}
165169

170+
threads_created = i;
171+
166172
sum = 0;
167173
memset(result, 0, sizeof(uint32) * THREAD_NUM);
168-
for (i = 0; i < THREAD_NUM; i++) {
174+
for (i = 0; i < threads_created; i++) {
169175
pthread_join(tid[i], (void **)&result[i]);
170176
sum += result[i];
171177
/* destroy the spawned exec_env */
172-
if (thread_arg[0].exec_env)
178+
if (thread_arg[i].exec_env)
173179
wasm_runtime_destroy_spawned_exec_env(thread_arg[i].exec_env);
174180
}
175181

@@ -191,15 +197,18 @@ int main(int argc, char *argv[])
191197
}
192198
}
193199

200+
threads_created = i;
201+
194202
sum = 0;
195203
memset(result, 0, sizeof(uint32) * THREAD_NUM);
196-
for (i = 0; i < THREAD_NUM; i++) {
204+
for (i = 0; i < threads_created; i++) {
197205
wasm_runtime_join_thread(wasm_tid[i], (void**)&result[i]);
198206
sum += result[i];
199207
/* No need to destroy the spawned exec_env */
200208
}
201209
printf("[spwan_thread]sum result: %d\n", sum);
202210

211+
fail5:
203212
wasm_runtime_destroy_exec_env(exec_env);
204213

205214
fail4:
@@ -217,4 +226,5 @@ int main(int argc, char *argv[])
217226
fail1:
218227
/* destroy runtime environment */
219228
wasm_runtime_destroy();
220-
}
229+
return 0;
230+
}

samples/wasm-c-api/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ set(EXAMPLES
9393
global
9494
reflect
9595
trap
96-
# multi # AOT/JIT return multiple values
97-
# globalexportimport # AOT/JIT doesn't suppport MULTI_MODULE
96+
callback_chain
9897
)
9998

10099
foreach(EX ${EXAMPLES})

samples/wasm-c-api/src/callback.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ int main(int argc, const char* argv[]) {
8484
wasm_byte_vec_new_uninitialized(&binary, file_size);
8585
if (fread(binary.data, file_size, 1, file) != 1) {
8686
printf("> Error loading module!\n");
87+
fclose(file);
8788
return 1;
8889
}
8990
fclose(file);
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
/*
2+
* Copyright (C) 2019 Intel Corporation. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
#include <inttypes.h>
10+
11+
#include "wasm_c_api.h"
12+
13+
#define own
14+
15+
static const byte_t *
16+
get_memory_data(uint32_t offset, uint32_t length);
17+
18+
static bool
19+
call_wasm_function(uint32_t export_id,
20+
const wasm_val_t *args,
21+
wasm_val_t *results,
22+
const char *name);
23+
24+
/************************ IMPORTED FUNCTIONS **************************/
25+
26+
// (nil) -> i32
27+
#define FUNCTION_TYPE_NIL_I32 wasm_functype_new_0_1(wasm_valtype_new_i32())
28+
// (i32, i32) -> nil
29+
#define FUNCTION_TYPE_I32X2_NIL \
30+
wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32())
31+
32+
/* IMPORT FUNCTION LIST */
33+
#define IMPORT_FUNCTION_LIST(V) \
34+
V(get_pairs, 0, FUNCTION_TYPE_NIL_I32) \
35+
V(log, 1, FUNCTION_TYPE_I32X2_NIL)
36+
37+
/* EXPORT FUNCTION LIST */
38+
#define EXPORT_FUNCTION_LIST(V) \
39+
V(on_start) \
40+
V(on_stop) \
41+
V(malloc) \
42+
V(free)
43+
44+
enum EXPORT_ITEM_NAME {
45+
#define DEFINE_ENUM(name) e_##name,
46+
EXPORT_FUNCTION_LIST(DEFINE_ENUM)
47+
#undef DEFINE_ENUM
48+
e_MEMORY,
49+
};
50+
51+
#define DEFINE_FUNCTION(name) \
52+
wasm_trap_t *STUB_##name(const wasm_val_t args[], wasm_val_t results[])
53+
54+
#define DEFINE_EMPTY_FUNCTION(name) \
55+
DEFINE_FUNCTION(name) \
56+
{ \
57+
printf("[WASM -> NATIVE] calling back %s\n", __FUNCTION__); \
58+
return NULL; \
59+
}
60+
#undef DEFINE_EMPTY_FUNCTION
61+
62+
DEFINE_FUNCTION(get_pairs)
63+
{
64+
wasm_val_t ret[1] = { WASM_INIT_VAL };
65+
call_wasm_function(e_malloc, (wasm_val_t[]){ WASM_I32_VAL(24) }, ret,
66+
"malloc");
67+
return NULL;
68+
}
69+
70+
DEFINE_FUNCTION(log)
71+
{
72+
wasm_val_t offset = args[0];
73+
wasm_val_t length = args[1];
74+
const byte_t *data = NULL;
75+
76+
printf("[WASM -> NATIVE] calling back %s\n", __FUNCTION__);
77+
78+
if (offset.kind != WASM_I32 || length.kind != WASM_I32) {
79+
printf("> Error value type!\n");
80+
}
81+
82+
if (!(data = get_memory_data(offset.of.i32, length.of.i32))) {
83+
return NULL;
84+
}
85+
86+
if (data[length.of.i32]) {
87+
printf("> Error terminated character\n");
88+
return NULL;
89+
}
90+
91+
printf("[WASM_LOG] %s\n", data);
92+
return NULL;
93+
}
94+
95+
static inline void
96+
create_import_function_list(wasm_store_t *store,
97+
const wasm_extern_t *import_function_list[])
98+
{
99+
#define IMPORT_FUNCTION_VARIABLE_NAME(name, ...) \
100+
own wasm_func_t *function_##name = NULL;
101+
IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME)
102+
#undef IMPORT_FUNCTION_VARIABLE_NAME
103+
104+
#define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \
105+
{ \
106+
own wasm_functype_t *type = CREATE_FUNC_TYPE; \
107+
if (!(function_##name = wasm_func_new(store, type, STUB_##name))) { \
108+
printf("> Error creating new function\n"); \
109+
} \
110+
wasm_functype_delete(type); \
111+
}
112+
IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION)
113+
#undef CREATE_WASM_FUNCTION
114+
115+
#define ADD_TO_FUNCTION_LIST(name, index, ...) \
116+
import_function_list[index] = wasm_func_as_extern(function_##name);
117+
IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST)
118+
#undef CREATE_IMPORT_FUNCTION
119+
}
120+
121+
/**********************************************************************/
122+
// all exportted wasm functions. check with "/opt/wabt/bin/wasm-objdump -x -j Export X.wasm"
123+
// -1: memory
124+
// 0-32: functions
125+
static own wasm_extern_vec_t exports = { 0 };
126+
127+
static const byte_t *
128+
get_memory_data(uint32_t offset, uint32_t length)
129+
{
130+
wasm_memory_t *memory;
131+
132+
if (!(memory = wasm_extern_as_memory(exports.data[e_MEMORY]))) {
133+
return NULL;
134+
}
135+
136+
byte_t *base = wasm_memory_data(memory);
137+
size_t size = wasm_memory_data_size(memory);
138+
if (!base || offset + length > size) {
139+
return NULL;
140+
}
141+
142+
printf("[NATIVE -> WASM] accessing the memory...\n");
143+
144+
return base + offset;
145+
}
146+
147+
static bool
148+
call_wasm_function(uint32_t export_id,
149+
const wasm_val_t *args,
150+
wasm_val_t *results,
151+
const char *name)
152+
{
153+
const wasm_func_t *function;
154+
wasm_trap_t *trap;
155+
156+
printf("[NATIVE -> WASM] calling func %s...\n", name);
157+
158+
if (!(function = wasm_extern_as_func(exports.data[export_id]))) {
159+
printf("> Error get export function %u\n", export_id);
160+
return false;
161+
}
162+
163+
if ((trap = wasm_func_call(function, args, results))) {
164+
own wasm_message_t message = { 0 };
165+
wasm_trap_message(trap, &message);
166+
167+
if (message.data) {
168+
printf("> Error calling function %s\n", message.data);
169+
}
170+
else {
171+
printf("> Error calling function");
172+
}
173+
174+
wasm_name_delete(&message);
175+
wasm_trap_delete(trap);
176+
return false;
177+
}
178+
return true;
179+
}
180+
181+
int
182+
main(int argc, const char *argv[])
183+
{
184+
// Initialize.
185+
printf("Initializing...\n");
186+
wasm_engine_t *engine = wasm_engine_new();
187+
wasm_store_t *store = wasm_store_new(engine);
188+
189+
// Load binary.
190+
printf("Loading binary...\n");
191+
FILE *file = fopen("callback_chain.wasm", "rb");
192+
if (!file) {
193+
printf("> Error loading module!\n");
194+
return 1;
195+
}
196+
fseek(file, 0L, SEEK_END);
197+
size_t file_size = ftell(file);
198+
fseek(file, 0L, SEEK_SET);
199+
wasm_byte_vec_t binary;
200+
wasm_byte_vec_new_uninitialized(&binary, file_size);
201+
if (fread(binary.data, file_size, 1, file) != 1) {
202+
printf("> Error loading module!\n");
203+
fclose(file);
204+
return 1;
205+
}
206+
fclose(file);
207+
208+
// Compile.
209+
printf("Compiling module...\n");
210+
own wasm_module_t *module = wasm_module_new(store, &binary);
211+
if (!module) {
212+
printf("> Error compiling module!\n");
213+
return 1;
214+
}
215+
216+
wasm_byte_vec_delete(&binary);
217+
218+
// Instantiate.
219+
printf("Instantiating module...\n");
220+
const wasm_extern_t *imports[10] = { 0 };
221+
222+
// Create external functions.
223+
printf("Creating callback...\n");
224+
create_import_function_list(store, imports);
225+
226+
own wasm_instance_t *instance =
227+
wasm_instance_new(store, module, imports, NULL);
228+
if (!instance) {
229+
printf("> Error instantiating module!\n");
230+
return 1;
231+
}
232+
233+
// Extract export.
234+
printf("Extracting export...\n");
235+
wasm_instance_exports(instance, &exports);
236+
if (!exports.size) {
237+
printf("> Error accessing exports!\n");
238+
return 1;
239+
}
240+
241+
wasm_module_delete(module);
242+
wasm_instance_delete(instance);
243+
244+
// Call.
245+
printf("Calling export...\n");
246+
247+
if (!call_wasm_function(e_on_start, NULL, NULL, "on_start")) {
248+
printf("> Error calling on_start\n");
249+
return 1;
250+
}
251+
252+
if (!call_wasm_function(e_on_stop, NULL, NULL, "on_stop")) {
253+
printf("> Error calling on_stop\n");
254+
return 1;
255+
}
256+
257+
wasm_extern_vec_delete(&exports);
258+
259+
// Shut down.
260+
printf("Shutting down...\n");
261+
wasm_store_delete(store);
262+
wasm_engine_delete(engine);
263+
264+
// All done.
265+
printf("Done.\n");
266+
return 0;
267+
}

0 commit comments

Comments
 (0)