Skip to content

Commit b366a78

Browse files
Maciejusiegl00
authored andcommitted
wamr: revitalize wamr handler
Signed-off-by: usiegl00 <[email protected]>
1 parent 52ed588 commit b366a78

File tree

5 files changed

+262
-3
lines changed

5 files changed

+262
-3
lines changed

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ libcrun_SOURCES = src/libcrun/utils.c \
5757
src/libcrun/handlers/wasmedge.c \
5858
src/libcrun/handlers/wasmer.c \
5959
src/libcrun/handlers/wasmtime.c \
60+
src/libcrun/handlers/wamr.c \
6061
src/libcrun/intelrdt.c \
6162
src/libcrun/io_priority.c \
6263
src/libcrun/linux.c \

configure.ac

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ dnl include support for wasmedge (EXPERIMENTAL)
124124
AC_ARG_WITH([wasmedge], AS_HELP_STRING([--with-wasmedge], [build with WasmEdge support]))
125125
AS_IF([test "x$with_wasmedge" = "xyes"], AC_CHECK_HEADERS([wasmedge/wasmedge.h], AC_DEFINE([HAVE_WASMEDGE], 1, [Define if WasmEdge is available]), [AC_MSG_ERROR([*** Missing wasmedge headers])]))
126126

127+
dnl include support for wamr (EXPERIMENTAL)
128+
AC_ARG_WITH([wamr], AS_HELP_STRING([--with-wamr], [build with WAMR support]))
129+
AS_IF([test "x$with_wamr" = "xyes"], AC_CHECK_HEADERS([wasm_export.h], AC_DEFINE([HAVE_WAMR], 1, [Define if WAMR is available]), [AC_MSG_ERROR([*** Missing WAMR headers])]))
130+
127131
dnl include support for libkrun (EXPERIMENTAL)
128132
AC_ARG_WITH([libkrun], AS_HELP_STRING([--with-libkrun], [build with libkrun support]))
129133
AS_IF([test "x$with_libkrun" = "xyes"], AC_CHECK_HEADERS([libkrun.h], AC_DEFINE([HAVE_LIBKRUN], 1, [Define if libkrun is available]), [AC_MSG_ERROR([*** Missing libkrun headers])]))

docs/wasm-wasi-on-kubernetes.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Running wasi workload natively on kubernetes using crun
22

3-
Crun natively supports running wasm/wasi workload on using `wasmedge`, `wasmer` and `wasmtime`.
4-
Each one of them (`wasmedge`, `wasmer` and `wasmtime`) comes with their own set of unique features.
5-
For instance `wasmer` can compile your `.wat` on the fly. Similarly `wasmedge` has its own perks.
3+
Crun natively supports running wasm/wasi workload on using `wasmedge`, `wasmer`, `wasmtime` and `wamr`.
4+
Each one of them (`wasmedge`, `wasmer`, `wasmtime` and `wamr`) comes with their own set of unique features.
5+
For instance `wasmer` can compile your `.wat` on the fly. Similarly `wasmedge` has its own perks. `wamr` has a layered JIT architecture which can tier up during runtime.
66
Crun can support only one of them at a time. Please build crun with whatever runtime suits you the best.
77

88
#### How does crun detects if is a wasm workload ?
@@ -31,6 +31,7 @@ So spec generated by CRI implementation must contain annotation something like.
3131

3232
* Following features works completely out if the box once `cri-o` is using `crun` built with `wasm` support.
3333
* Configure `cri-o` to use `crun` instead of `runc` by editing config at `/etc/crio/crio.conf` read more about it here https://docs.openshift.com/container-platform/3.11/crio/crio_runtime.html#configure-crio-use-crio-engine
34+
* As of `cri-o` version `1.31` it defaults to `crun`, but the bundled `crun` may not have been built with `wasm` support.
3435
* Restart `cri-o` by `sudo systemctl restart crio`
3536
* `cri-o` automatically propagates pod annotations to container spec. So we don't need to do anything.
3637

src/libcrun/custom-handler.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ extern struct custom_handler_s handler_wasmedge;
4545
#if HAVE_DLOPEN && HAVE_WASMER
4646
extern struct custom_handler_s handler_wasmer;
4747
#endif
48+
#if HAVE_DLOPEN && HAVE_WAMR
49+
extern struct custom_handler_s handler_wamr;
50+
#endif
4851
#if HAVE_DLOPEN && HAVE_MONO
4952
extern struct custom_handler_s handler_mono;
5053
#endif
@@ -65,6 +68,9 @@ static struct custom_handler_s *static_handlers[] = {
6568
#if HAVE_DLOPEN && HAVE_WASMTIME
6669
&handler_wasmtime,
6770
#endif
71+
#if HAVE_DLOPEN && HAVE_WAMR
72+
&handler_wamr,
73+
#endif
6874
#if HAVE_DLOPEN && HAVE_MONO
6975
&handler_mono,
7076
#endif

src/libcrun/handlers/wamr.c

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/*
2+
* crun - OCI runtime written in C
3+
*
4+
* Copyright (C) 2017, 2018, 2019, 2020, 2021 Giuseppe Scrivano <[email protected]>
5+
* crun is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation; either version 2.1 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* crun is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with crun. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
#define _GNU_SOURCE
19+
20+
#include <config.h>
21+
#include "../custom-handler.h"
22+
#include "../container.h"
23+
#include "../utils.h"
24+
#include "../linux.h"
25+
#include "handler-utils.h"
26+
#include <unistd.h>
27+
#include <sys/stat.h>
28+
#include <errno.h>
29+
#include <sys/types.h>
30+
#include <fcntl.h>
31+
#include <sched.h>
32+
#include <stdio.h>
33+
#include <stdlib.h>
34+
35+
#ifdef HAVE_DLOPEN
36+
# include <dlfcn.h>
37+
#endif
38+
39+
#ifdef HAVE_WAMR
40+
# include <wasm_export.h>
41+
#endif
42+
43+
#if HAVE_DLOPEN && HAVE_WAMR
44+
45+
static int
46+
libwamr_load (void **cookie, libcrun_error_t *err)
47+
{
48+
void *handle;
49+
50+
handle = dlopen ("libiwasm.so", RTLD_NOW);
51+
if (handle == NULL)
52+
return crun_make_error (err, 0, "could not load `libiwasm.so`: `%s`", dlerror ());
53+
*cookie = handle;
54+
55+
return 0;
56+
}
57+
58+
static int
59+
libwamr_unload (void *cookie, libcrun_error_t *err)
60+
{
61+
int r;
62+
63+
if (cookie)
64+
{
65+
r = dlclose (cookie);
66+
if (UNLIKELY (r < 0))
67+
return crun_make_error (err, 0, "could not unload handle: `%s`", dlerror ());
68+
}
69+
return 0;
70+
}
71+
72+
static int
73+
libwamr_exec (void *cookie, __attribute__ ((unused)) libcrun_container_t *container, const char *pathname, char *const argv[])
74+
{
75+
// load symbols from the shared library libiwasm.so
76+
bool (*wasm_runtime_init) ();
77+
RuntimeInitArgs init_args;
78+
bool (*wasm_runtime_full_init) (RuntimeInitArgs *init_args);
79+
wasm_module_t module;
80+
wasm_module_t (*wasm_runtime_load) (uint8_t *buf, uint32_t size, char *error_buf, uint32_t error_buf_size);
81+
wasm_module_inst_t module_inst;
82+
wasm_module_inst_t (*wasm_runtime_instantiate) (const wasm_module_t module, uint32_t default_stack_size, uint32_t host_managed_heap_size, char *error_buf, uint32_t error_buf_size);
83+
wasm_function_inst_t func;
84+
wasm_function_inst_t (*wasm_runtime_lookup_function) (wasm_module_inst_t const module_inst, const char *name);
85+
wasm_exec_env_t exec_env;
86+
wasm_exec_env_t (*wasm_runtime_create_exec_env) (wasm_module_inst_t module_inst, uint32_t stack_size);
87+
bool (*wasm_runtime_call_wasm) (wasm_exec_env_t exec_env, wasm_function_inst_t function, uint32_t argc, uint32_t argv[]);
88+
const char *(*wasm_runtime_get_exception) (wasm_module_inst_t module_inst);
89+
void (*wasm_runtime_set_exception) (wasm_module_inst_t module_inst, const char *exception);
90+
void (*wasm_runtime_clear_exception) (wasm_module_inst_t module_inst);
91+
void (*wasm_runtime_destroy_exec_env) (wasm_exec_env_t exec_env);
92+
void (*wasm_runtime_deinstantiate) (wasm_module_inst_t module_inst);
93+
void (*wasm_runtime_unload) (wasm_module_t module);
94+
void (*wasm_runtime_destroy) ();
95+
uint32_t (*wasm_runtime_get_wasi_exit_code) (wasm_module_inst_t module_inst);
96+
bool (*wasm_application_execute_main) (wasm_module_inst_t module_inst, int32_t argc, char *argv[]);
97+
void (*wasm_runtime_set_wasi_args) (wasm_module_t module, const char *dir_list[], uint32_t dir_count, const char *map_dir_list[], uint32_t map_dir_count, const char *env[], uint32_t env_count, char *argv[], int argc);
98+
99+
wasm_runtime_init = dlsym (cookie, "wasm_runtime_init");
100+
wasm_runtime_full_init = dlsym (cookie, "wasm_runtime_full_init");
101+
wasm_runtime_load = dlsym (cookie, "wasm_runtime_load");
102+
wasm_runtime_instantiate = dlsym (cookie, "wasm_runtime_instantiate");
103+
wasm_runtime_lookup_function = dlsym (cookie, "wasm_runtime_lookup_function");
104+
wasm_runtime_create_exec_env = dlsym (cookie, "wasm_runtime_create_exec_env");
105+
wasm_runtime_call_wasm = dlsym (cookie, "wasm_runtime_call_wasm");
106+
wasm_runtime_get_exception = dlsym (cookie, "wasm_runtime_get_exception");
107+
wasm_runtime_set_exception = dlsym (cookie, "wasm_runtime_set_exception");
108+
wasm_runtime_clear_exception = dlsym (cookie, "wasm_runtime_clear_exception");
109+
wasm_runtime_destroy_exec_env = dlsym (cookie, "wasm_runtime_destroy_exec_env");
110+
wasm_runtime_deinstantiate = dlsym (cookie, "wasm_runtime_deinstantiate");
111+
wasm_runtime_unload = dlsym (cookie, "wasm_runtime_unload");
112+
wasm_runtime_destroy = dlsym (cookie, "wasm_runtime_destroy");
113+
wasm_runtime_get_wasi_exit_code = dlsym (cookie, "wasm_runtime_get_wasi_exit_code");
114+
wasm_application_execute_main = dlsym (cookie, "wasm_application_execute_main");
115+
wasm_runtime_set_wasi_args = dlsym (cookie, "wasm_runtime_set_wasi_args");
116+
117+
if (wasm_runtime_init == NULL)
118+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_init symbol in `libiwasm.so`");
119+
if (wasm_runtime_full_init == NULL)
120+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_full_init symbol in `libiwasm.so`");
121+
if (wasm_runtime_load == NULL)
122+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_load symbol in `libiwasm.so`");
123+
if (wasm_runtime_instantiate == NULL)
124+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_instantiate symbol in `libiwasm.so`");
125+
if (wasm_runtime_lookup_function == NULL)
126+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_lookup_function symbol in `libiwasm.so`");
127+
if (wasm_runtime_create_exec_env == NULL)
128+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_create_exec_env symbol in `libiwasm.so`");
129+
if (wasm_runtime_call_wasm == NULL)
130+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_call_wasm symbol in `libiwasm.so`");
131+
if (wasm_runtime_get_exception == NULL)
132+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_get_exception symbol in `libiwasm.so`");
133+
if (wasm_runtime_set_exception == NULL)
134+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_set_exception symbol in `libiwasm.so`");
135+
if (wasm_runtime_clear_exception == NULL)
136+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_clear_exception symbol in `libiwasm.so`");
137+
if (wasm_runtime_destroy_exec_env == NULL)
138+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_destroy_exec_env symbol in `libiwasm.so`");
139+
if (wasm_runtime_deinstantiate == NULL)
140+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_deinstantiate symbol in `libiwasm.so`");
141+
if (wasm_runtime_unload == NULL)
142+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_unload symbol in `libiwasm.so`");
143+
if (wasm_runtime_destroy == NULL)
144+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_destroy symbol in `libiwasm.so`");
145+
if (wasm_runtime_get_wasi_exit_code == NULL)
146+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_get_wasi_exit_code symbol in `libiwasm.so`");
147+
if (wasm_application_execute_main == NULL)
148+
error (EXIT_FAILURE, 0, "could not find wasm_application_execute_main symbol in `libiwasm.so`");
149+
if (wasm_runtime_set_wasi_args == NULL)
150+
error (EXIT_FAILURE, 0, "could not find wasm_runtime_set_wasi_args symbol in `libiwasm.so`");
151+
152+
int ret;
153+
const char *exception;
154+
cleanup_free char *buffer = NULL;
155+
char error_buf[128];
156+
size_t buffer_size;
157+
uint32_t stack_size = 8096, heap_size = 0;
158+
libcrun_error_t tmp_err = NULL;
159+
const char *wasi_proc_exit_exception = "wasi proc exit";
160+
const char *wasi_addr_pool[2] = { "0.0.0.0/0", "::/0" };
161+
const char *wasi_ns_lookup_pool[1] = { "*" };
162+
163+
const char *dirs[2] = { "/", "." };
164+
char **container_env = container->container_def->process->env;
165+
size_t env_count = container->container_def->process->env_len;
166+
167+
int arg_count = 0;
168+
char *const *arg;
169+
for (arg = argv; *arg != NULL; ++arg)
170+
arg_count++;
171+
172+
// initialize the wasm runtime by default configurations
173+
if (! wasm_runtime_init ())
174+
error (EXIT_FAILURE, 0, "Failed to initialize the wasm runtime");
175+
176+
// read WASM file into a memory buffer
177+
ret = read_all_file (pathname, &buffer, &buffer_size, &tmp_err);
178+
if (UNLIKELY (ret < 0))
179+
{
180+
crun_error_release (&tmp_err);
181+
error (EXIT_FAILURE, 0, "Failed to read file");
182+
}
183+
184+
if (UNLIKELY (buffer_size > UINT32_MAX))
185+
error (EXIT_FAILURE, 0, "File size is too large");
186+
187+
// parse the WASM file from buffer and create a WASM module
188+
module = wasm_runtime_load (buffer, buffer_size, error_buf, sizeof (error_buf));
189+
if (! module)
190+
error (EXIT_FAILURE, 0, "Failed to load WASM file");
191+
192+
// instantiate the WASI environment
193+
wasm_runtime_set_wasi_args (module, dirs, 1, NULL, 0, (const char **) container_env, env_count, (char **) argv, arg_count);
194+
195+
// enable the WASI socket api
196+
wasm_runtime_set_wasi_addr_pool (module, wasi_addr_pool, 2);
197+
wasm_runtime_set_wasi_ns_lookup_pool (module, wasi_ns_lookup_pool, 1);
198+
199+
// create an instance of the WASM module (WASM linear memory is ready)
200+
module_inst = wasm_runtime_instantiate (module, stack_size, heap_size, error_buf, sizeof (error_buf));
201+
if (! module_inst)
202+
error (EXIT_FAILURE, 0, "Failed to instantiate the WASM module");
203+
204+
// look up a WASM function by its name (The function signature can NULL here)
205+
func = wasm_runtime_lookup_function (module_inst, "_start");
206+
if (! func)
207+
error (EXIT_FAILURE, 0, "Failed to look up the WASM function");
208+
209+
// create an execution environment to execute the WASM functions
210+
exec_env = wasm_runtime_create_exec_env (module_inst, stack_size);
211+
if (! exec_env)
212+
error (EXIT_FAILURE, 0, "Failed to create the execution environment");
213+
214+
// call the WASM function
215+
ret = wasm_runtime_call_wasm (exec_env, func, 0, NULL);
216+
if (ret)
217+
wasm_runtime_set_exception (module_inst, wasi_proc_exit_exception);
218+
exception = wasm_runtime_get_exception (module_inst);
219+
if (! strstr (exception, wasi_proc_exit_exception))
220+
error (EXIT_FAILURE, 0, "Failed to call the WASM function");
221+
wasm_runtime_clear_exception (module_inst);
222+
223+
wasm_runtime_destroy_exec_env (exec_env);
224+
wasm_runtime_deinstantiate (module_inst);
225+
wasm_runtime_unload (module);
226+
wasm_runtime_destroy ();
227+
228+
exit (EXIT_SUCCESS);
229+
}
230+
231+
static int
232+
libwamr_can_handle_container (libcrun_container_t *container, libcrun_error_t *err)
233+
{
234+
return wasm_can_handle_container (container, err);
235+
}
236+
237+
struct custom_handler_s handler_wamr = {
238+
.name = "wamr",
239+
.alias = "wasm",
240+
.feature_string = "WASM:wamr",
241+
.load = libwamr_load,
242+
.unload = libwamr_unload,
243+
.run_func = libwamr_exec,
244+
.can_handle_container = libwamr_can_handle_container,
245+
};
246+
247+
#endif

0 commit comments

Comments
 (0)