From 684ae6554d9597ff027fa8e5ca797da1fa052375 Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Tue, 6 Dec 2022 13:11:27 +0000 Subject: [PATCH] Create a placeholder for WASI threads implementation (#1783) This a simpler version of the PR: https://github.com/bytecodealliance/wasm-micro-runtime/pull/1638 --- CMakeLists.txt | 5 ++ build-scripts/runtime_lib.cmake | 8 ++ core/config.h | 4 + core/iwasm/common/wasm_native.c | 17 +++- .../lib-wasi-threads/lib_wasi_threads.cmake | 11 +++ .../lib_wasi_threads_wrapper.c | 35 ++++++++ product-mini/platforms/linux/CMakeLists.txt | 6 ++ samples/wasi-threads/CMakeLists.txt | 87 +++++++++++++++++++ samples/wasi-threads/README.md | 1 + samples/wasi-threads/wasm-apps/CMakeLists.txt | 29 +++++++ samples/wasi-threads/wasm-apps/no_pthread.c | 55 ++++++++++++ 11 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake create mode 100644 core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c create mode 100644 samples/wasi-threads/CMakeLists.txt create mode 100644 samples/wasi-threads/README.md create mode 100644 samples/wasi-threads/wasm-apps/CMakeLists.txt create mode 100644 samples/wasi-threads/wasm-apps/no_pthread.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f683868f..d6466ba5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,11 @@ if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) set (WAMR_BUILD_LIB_PTHREAD 0) endif () +if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS) + # Disable wasi threads library by default + set (WAMR_BUILD_LIB_WASI_THREADS 0) +endif () + if (NOT DEFINED WAMR_BUILD_MINI_LOADER) # Disable wasm mini loader by default set (WAMR_BUILD_MINI_LOADER 0) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 439a7c63..b6e6cd06 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -124,6 +124,13 @@ if (WAMR_BUILD_LIB_PTHREAD EQUAL 1) set (WAMR_BUILD_SHARED_MEMORY 1) endif () +if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1) + include (${IWASM_DIR}/libraries/lib-wasi-threads/lib_wasi_threads.cmake) + # Enable the dependent feature if lib wasi threads is enabled + set (WAMR_BUILD_BULK_MEMORY 1) + set (WAMR_BUILD_SHARED_MEMORY 1) +endif () + if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_THREAD_MGR 1) include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake) @@ -186,6 +193,7 @@ set (source_all ${WASM_APP_LIB_SOURCE_ALL} ${NATIVE_INTERFACE_SOURCE} ${APP_MGR_SOURCE} + ${LIB_WASI_THREADS_SOURCE} ${LIB_PTHREAD_SOURCE} ${THREAD_MGR_SOURCE} ${LIBC_EMCC_SOURCE} diff --git a/core/config.h b/core/config.h index 5d643838..2b6846e4 100644 --- a/core/config.h +++ b/core/config.h @@ -161,6 +161,10 @@ #define WASM_ENABLE_LIB_PTHREAD_SEMAPHORE 0 #endif +#ifndef WASM_ENABLE_LIB_WASI_THREADS +#define WASM_ENABLE_LIB_WASI_THREADS 0 +#endif + #ifndef WASM_ENABLE_BASE_LIB #define WASM_ENABLE_BASE_LIB 0 #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 0fa59627..8c324cdc 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -53,6 +53,11 @@ uint32 get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis); #endif +#if WASM_ENABLE_LIB_WASI_THREADS != 0 +uint32 +get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis); +#endif + uint32 get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis); @@ -383,7 +388,7 @@ wasm_native_init() || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ - || WASM_ENABLE_LIB_PTHREAD != 0 + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 NativeSymbol *native_symbols; uint32 n_native_symbols; #endif @@ -438,6 +443,14 @@ wasm_native_init() goto fail; #endif +#if WASM_ENABLE_LIB_WASI_THREADS != 0 + n_native_symbols = get_lib_wasi_threads_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("wasi", native_symbols, + n_native_symbols)) + goto fail; +#endif + #if WASM_ENABLE_LIBC_EMCC != 0 n_native_symbols = get_libc_emcc_export_apis(&native_symbols); if (n_native_symbols > 0 @@ -466,7 +479,7 @@ wasm_native_init() || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ - || WASM_ENABLE_LIB_PTHREAD != 0 + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 fail: wasm_native_destroy(); return false; diff --git a/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake b/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake new file mode 100644 index 00000000..2f300be5 --- /dev/null +++ b/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake @@ -0,0 +1,11 @@ +# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIB_WASI_THREADS_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIB_WASI_THREADS=1) + +include_directories(${LIB_WASI_THREADS_DIR}) + +set (LIB_WASI_THREADS_SOURCE + ${LIB_WASI_THREADS_DIR}/lib_wasi_threads_wrapper.c) \ No newline at end of file diff --git a/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c b/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c new file mode 100644 index 00000000..4412a5be --- /dev/null +++ b/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasmtime_ssp.h" + +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif + +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +static __wasi_errno_t +thread_spawn_wrapper(wasm_exec_env_t exec_env, void *start_arg) +{ + return __WASI_ENOSYS; +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_lib_wasi_threads[] = { REG_NATIVE_FUNC( + thread_spawn, "(*)i") }; + +uint32 +get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis) +{ + *p_lib_wasi_threads_apis = native_symbols_lib_wasi_threads; + return sizeof(native_symbols_lib_wasi_threads) / sizeof(NativeSymbol); +} diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index d3285be1..7f846308 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -85,6 +85,12 @@ if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) set (WAMR_BUILD_LIB_PTHREAD 0) endif () +if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS) + # Disable wasi threads library by default + set (WAMR_BUILD_LIB_WASI_THREADS 0) +endif() + + if (NOT DEFINED WAMR_BUILD_MINI_LOADER) # Disable wasm mini loader by default set (WAMR_BUILD_MINI_LOADER 0) diff --git a/samples/wasi-threads/CMakeLists.txt b/samples/wasi-threads/CMakeLists.txt new file mode 100644 index 00000000..93f6b331 --- /dev/null +++ b/samples/wasi-threads/CMakeLists.txt @@ -0,0 +1,87 @@ +# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) + +include(CheckPIESupported) + +project(wasi_threads_sample) + +if (NOT DEFINED WASI_SYSROOT) + message (WARNING "Custom sysroot with threads enabled is required to build wasi threads samples. +Please note that current wasi-sdk doesn't ship with threads enabled. +Run cmake command with -DWASI_SYSROOT=/path/to/sysroot/with/threads to compile samples.") + return () +endif () + +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Release) +endif () + +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_AOT 1) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_LIB_WASI_THREADS 1) + +# compiling and linking flags +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +################################################ + + +################ wasm application ################ +add_subdirectory(wasm-apps) + +################ wamr runtime ################ +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +set (RUNTIME_SOURCE_ALL + ${CMAKE_CURRENT_LIST_DIR}/../../product-mini/platforms/linux/main.c + ${UNCOMMON_SHARED_SOURCE} +) +add_executable (iwasm ${RUNTIME_SOURCE_ALL}) +check_pie_supported() +set_target_properties (iwasm PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_link_libraries(iwasm vmlib -lpthread -lm -ldl) diff --git a/samples/wasi-threads/README.md b/samples/wasi-threads/README.md new file mode 100644 index 00000000..d7450af9 --- /dev/null +++ b/samples/wasi-threads/README.md @@ -0,0 +1 @@ +# "WASI threads" sample introduction \ No newline at end of file diff --git a/samples/wasi-threads/wasm-apps/CMakeLists.txt b/samples/wasi-threads/wasm-apps/CMakeLists.txt new file mode 100644 index 00000000..9e3bef5a --- /dev/null +++ b/samples/wasi-threads/wasm-apps/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +if (NOT DEFINED WASI_SDK_DIR) + set (WASI_SDK_DIR "/opt/wasi-sdk") +endif () + +set (CMAKE_SYSROOT "${WASI_SYSROOT}") +set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") +set (CMAKE_C_COMPILER_TARGET "wasm32-wasi") + +function (compile_sample SOURCE_FILE) + get_filename_component (FILE_NAME ${SOURCE_FILE} NAME_WLE) + set (WASM_MODULE ${FILE_NAME}.wasm) + add_executable (${WASM_MODULE} ${SOURCE_FILE}) + + target_compile_options (${WASM_MODULE} PRIVATE + -pthread -ftls-model=local-exec) + + target_link_options (${WASM_MODULE} PRIVATE + -z stack-size=32768 + LINKER:--export=__heap_base + LINKER:--export=__data_end + LINKER:--shared-memory,--max-memory=1966080 + LINKER:--export=wasi_thread_start + ) +endfunction () + +compile_sample(no_pthread.c) diff --git a/samples/wasi-threads/wasm-apps/no_pthread.c b/samples/wasi-threads/wasm-apps/no_pthread.c new file mode 100644 index 00000000..3de2a960 --- /dev/null +++ b/samples/wasi-threads/wasm-apps/no_pthread.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include +#include +#include + +static const int64_t SECOND = 1000 * 1000 * 1000; + +typedef struct { + int th_ready; + int value; +} shared_t; + +__attribute__((export_name("wasi_thread_start"))) void +wasi_thread_start(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + printf("New thread ID: %d, starting parameter: %d\n", thread_id, + data->value); + + data->value += 8; + printf("Updated value: %d\n", data->value); + + data->th_ready = 1; + __builtin_wasm_memory_atomic_notify(&data->th_ready, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data = { 0, 52 }; + __wasi_errno_t err; + + err = __wasi_thread_spawn(&data); + if (err != __WASI_ERRNO_SUCCESS) { + printf("Failed to create thread: %d\n", err); + return EXIT_FAILURE; + } + + if (__builtin_wasm_memory_atomic_wait32(&data.th_ready, 0, SECOND) == 2) { + printf("Timeout\n"); + return EXIT_FAILURE; + } + + printf("Thread completed, new value: %d\n", data.value); + + return EXIT_SUCCESS; +}