summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c')
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c680
1 files changed, 680 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c
new file mode 100644
index 000000000..5e814c418
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include "platform_api_vmcore.h"
+#include "platform_api_extension.h"
+
+typedef struct {
+ thread_start_routine_t start;
+ void *arg;
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ os_signal_handler signal_handler;
+#endif
+} thread_wrapper_arg;
+
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+/* The signal handler passed to os_thread_signal_init() */
+static os_thread_local_attribute os_signal_handler signal_handler;
+#endif
+
+static void *
+os_thread_wrapper(void *arg)
+{
+ thread_wrapper_arg *targ = arg;
+ thread_start_routine_t start_func = targ->start;
+ void *thread_arg = targ->arg;
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ os_signal_handler handler = targ->signal_handler;
+#endif
+
+#if 0
+ os_printf("THREAD CREATED %jx\n", (uintmax_t)(uintptr_t)pthread_self());
+#endif
+ BH_FREE(targ);
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ if (os_thread_signal_init(handler) != 0)
+ return NULL;
+#endif
+ start_func(thread_arg);
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ os_thread_signal_destroy();
+#endif
+ return NULL;
+}
+
+int
+os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
+ void *arg, unsigned int stack_size, int prio)
+{
+ pthread_attr_t tattr;
+ thread_wrapper_arg *targ;
+
+ assert(stack_size > 0);
+ assert(tid);
+ assert(start);
+
+ pthread_attr_init(&tattr);
+ pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
+ if (pthread_attr_setstacksize(&tattr, stack_size) != 0) {
+ os_printf("Invalid thread stack size %u. "
+ "Min stack size on Linux = %u\n",
+ stack_size, (unsigned int)PTHREAD_STACK_MIN);
+ pthread_attr_destroy(&tattr);
+ return BHT_ERROR;
+ }
+
+ targ = (thread_wrapper_arg *)BH_MALLOC(sizeof(*targ));
+ if (!targ) {
+ pthread_attr_destroy(&tattr);
+ return BHT_ERROR;
+ }
+
+ targ->start = start;
+ targ->arg = arg;
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ targ->signal_handler = signal_handler;
+#endif
+
+ if (pthread_create(tid, &tattr, os_thread_wrapper, targ) != 0) {
+ pthread_attr_destroy(&tattr);
+ BH_FREE(targ);
+ return BHT_ERROR;
+ }
+
+ pthread_attr_destroy(&tattr);
+ return BHT_OK;
+}
+
+int
+os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
+ unsigned int stack_size)
+{
+ return os_thread_create_with_prio(tid, start, arg, stack_size,
+ BH_THREAD_DEFAULT_PRIORITY);
+}
+
+korp_tid
+os_self_thread()
+{
+ return (korp_tid)pthread_self();
+}
+
+int
+os_mutex_init(korp_mutex *mutex)
+{
+ return pthread_mutex_init(mutex, NULL) == 0 ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_recursive_mutex_init(korp_mutex *mutex)
+{
+ int ret;
+
+ pthread_mutexattr_t mattr;
+
+ assert(mutex);
+ ret = pthread_mutexattr_init(&mattr);
+ if (ret)
+ return BHT_ERROR;
+
+ pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
+ ret = pthread_mutex_init(mutex, &mattr);
+ pthread_mutexattr_destroy(&mattr);
+
+ return ret == 0 ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_mutex_destroy(korp_mutex *mutex)
+{
+ int ret;
+
+ assert(mutex);
+ ret = pthread_mutex_destroy(mutex);
+
+ return ret == 0 ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_mutex_lock(korp_mutex *mutex)
+{
+ int ret;
+
+ assert(mutex);
+ ret = pthread_mutex_lock(mutex);
+
+ return ret == 0 ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_mutex_unlock(korp_mutex *mutex)
+{
+ int ret;
+
+ assert(mutex);
+ ret = pthread_mutex_unlock(mutex);
+
+ return ret == 0 ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_cond_init(korp_cond *cond)
+{
+ assert(cond);
+
+ if (pthread_cond_init(cond, NULL) != BHT_OK)
+ return BHT_ERROR;
+
+ return BHT_OK;
+}
+
+int
+os_cond_destroy(korp_cond *cond)
+{
+ assert(cond);
+
+ if (pthread_cond_destroy(cond) != BHT_OK)
+ return BHT_ERROR;
+
+ return BHT_OK;
+}
+
+int
+os_cond_wait(korp_cond *cond, korp_mutex *mutex)
+{
+ assert(cond);
+ assert(mutex);
+
+ if (pthread_cond_wait(cond, mutex) != BHT_OK)
+ return BHT_ERROR;
+
+ return BHT_OK;
+}
+
+korp_sem *
+os_sem_open(const char *name, int oflags, int mode, int val)
+{
+ return sem_open(name, oflags, mode, val);
+}
+
+int
+os_sem_close(korp_sem *sem)
+{
+ return sem_close(sem);
+}
+
+int
+os_sem_wait(korp_sem *sem)
+{
+ return sem_wait(sem);
+}
+
+int
+os_sem_trywait(korp_sem *sem)
+{
+ return sem_trywait(sem);
+}
+
+int
+os_sem_post(korp_sem *sem)
+{
+ return sem_post(sem);
+}
+
+int
+os_sem_getvalue(korp_sem *sem, int *sval)
+{
+#if defined(__APPLE__)
+ /*
+ * macOS doesn't have working sem_getvalue.
+ * It's marked as deprecated in the system header.
+ * Mock it up here to avoid compile-time deprecation warnings.
+ */
+ errno = ENOSYS;
+ return -1;
+#else
+ return sem_getvalue(sem, sval);
+#endif
+}
+
+int
+os_sem_unlink(const char *name)
+{
+ return sem_unlink(name);
+}
+
+static void
+msec_nsec_to_abstime(struct timespec *ts, uint64 usec)
+{
+ struct timeval tv;
+ time_t tv_sec_new;
+ long int tv_nsec_new;
+
+ gettimeofday(&tv, NULL);
+
+ tv_sec_new = (time_t)(tv.tv_sec + usec / 1000000);
+ if (tv_sec_new >= tv.tv_sec) {
+ ts->tv_sec = tv_sec_new;
+ }
+ else {
+ /* integer overflow */
+ ts->tv_sec = BH_TIME_T_MAX;
+ os_printf("Warning: os_cond_reltimedwait exceeds limit, "
+ "set to max timeout instead\n");
+ }
+
+ tv_nsec_new = (long int)(tv.tv_usec * 1000 + (usec % 1000000) * 1000);
+ if (tv.tv_usec * 1000 >= tv.tv_usec && tv_nsec_new >= tv.tv_usec * 1000) {
+ ts->tv_nsec = tv_nsec_new;
+ }
+ else {
+ /* integer overflow */
+ ts->tv_nsec = LONG_MAX;
+ os_printf("Warning: os_cond_reltimedwait exceeds limit, "
+ "set to max timeout instead\n");
+ }
+
+ if (ts->tv_nsec >= 1000000000L && ts->tv_sec < BH_TIME_T_MAX) {
+ ts->tv_sec++;
+ ts->tv_nsec -= 1000000000L;
+ }
+}
+
+int
+os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds)
+{
+ int ret;
+ struct timespec abstime;
+
+ if (useconds == BHT_WAIT_FOREVER)
+ ret = pthread_cond_wait(cond, mutex);
+ else {
+ msec_nsec_to_abstime(&abstime, useconds);
+ ret = pthread_cond_timedwait(cond, mutex, &abstime);
+ }
+
+ if (ret != BHT_OK && ret != ETIMEDOUT)
+ return BHT_ERROR;
+
+ return ret;
+}
+
+int
+os_cond_signal(korp_cond *cond)
+{
+ assert(cond);
+
+ if (pthread_cond_signal(cond) != BHT_OK)
+ return BHT_ERROR;
+
+ return BHT_OK;
+}
+
+int
+os_cond_broadcast(korp_cond *cond)
+{
+ assert(cond);
+
+ if (pthread_cond_broadcast(cond) != BHT_OK)
+ return BHT_ERROR;
+
+ return BHT_OK;
+}
+
+int
+os_thread_join(korp_tid thread, void **value_ptr)
+{
+ return pthread_join(thread, value_ptr);
+}
+
+int
+os_thread_detach(korp_tid thread)
+{
+ return pthread_detach(thread);
+}
+
+void
+os_thread_exit(void *retval)
+{
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ os_thread_signal_destroy();
+#endif
+ return pthread_exit(retval);
+}
+
+#if defined(os_thread_local_attribute)
+static os_thread_local_attribute uint8 *thread_stack_boundary = NULL;
+#endif
+
+uint8 *
+os_thread_get_stack_boundary()
+{
+ pthread_t self;
+#ifdef __linux__
+ pthread_attr_t attr;
+ size_t guard_size;
+#endif
+ uint8 *addr = NULL;
+ size_t stack_size, max_stack_size;
+ int page_size;
+
+#if defined(os_thread_local_attribute)
+ if (thread_stack_boundary)
+ return thread_stack_boundary;
+#endif
+
+ page_size = getpagesize();
+ self = pthread_self();
+ max_stack_size =
+ (size_t)(APP_THREAD_STACK_SIZE_MAX + page_size - 1) & ~(page_size - 1);
+
+ if (max_stack_size < APP_THREAD_STACK_SIZE_DEFAULT)
+ max_stack_size = APP_THREAD_STACK_SIZE_DEFAULT;
+
+#ifdef __linux__
+ if (pthread_getattr_np(self, &attr) == 0) {
+ pthread_attr_getstack(&attr, (void **)&addr, &stack_size);
+ pthread_attr_getguardsize(&attr, &guard_size);
+ pthread_attr_destroy(&attr);
+ if (stack_size > max_stack_size)
+ addr = addr + stack_size - max_stack_size;
+ if (guard_size < (size_t)page_size)
+ /* Reserved 1 guard page at least for safety */
+ guard_size = (size_t)page_size;
+ addr += guard_size;
+ }
+ (void)stack_size;
+#elif defined(__APPLE__) || defined(__NuttX__)
+ if ((addr = (uint8 *)pthread_get_stackaddr_np(self))) {
+ stack_size = pthread_get_stacksize_np(self);
+
+ /**
+ * Check whether stack_addr is the base or end of the stack,
+ * change it to the base if it is the end of stack.
+ */
+ if (addr <= (uint8 *)&stack_size)
+ addr = addr + stack_size;
+
+ if (stack_size > max_stack_size)
+ stack_size = max_stack_size;
+
+ addr -= stack_size;
+ /* Reserved 1 guard page at least for safety */
+ addr += page_size;
+ }
+#endif
+
+#if defined(os_thread_local_attribute)
+ thread_stack_boundary = addr;
+#endif
+ return addr;
+}
+
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+
+#define SIG_ALT_STACK_SIZE (32 * 1024)
+
+/**
+ * Whether thread signal enviornment is initialized:
+ * the signal handler is registered, the stack pages are touched,
+ * the stack guard pages are set and signal alternate stack are set.
+ */
+static os_thread_local_attribute bool thread_signal_inited = false;
+
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+/* The signal alternate stack base addr */
+static os_thread_local_attribute uint8 *sigalt_stack_base_addr;
+
+#if defined(__clang__)
+#pragma clang optimize off
+#elif defined(__GNUC__)
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+__attribute__((no_sanitize_address))
+#endif
+static uint32
+touch_pages(uint8 *stack_min_addr, uint32 page_size)
+{
+ uint8 sum = 0;
+ while (1) {
+ volatile uint8 *touch_addr = (volatile uint8 *)os_alloca(page_size / 2);
+ if (touch_addr < stack_min_addr + page_size) {
+ sum += *(stack_min_addr + page_size - 1);
+ break;
+ }
+ *touch_addr = 0;
+ sum += *touch_addr;
+ }
+ return sum;
+}
+#if defined(__clang__)
+#pragma clang optimize on
+#elif defined(__GNUC__)
+#pragma GCC pop_options
+#endif
+
+static bool
+init_stack_guard_pages()
+{
+ uint32 page_size = os_getpagesize();
+ uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
+ uint8 *stack_min_addr = os_thread_get_stack_boundary();
+
+ if (stack_min_addr == NULL)
+ return false;
+
+ /* Touch each stack page to ensure that it has been mapped: the OS
+ may lazily grow the stack mapping as a guard page is hit. */
+ (void)touch_pages(stack_min_addr, page_size);
+ /* First time to call aot function, protect guard pages */
+ if (os_mprotect(stack_min_addr, page_size * guard_page_count,
+ MMAP_PROT_NONE)
+ != 0) {
+ return false;
+ }
+ return true;
+}
+
+static void
+destroy_stack_guard_pages()
+{
+ uint32 page_size = os_getpagesize();
+ uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
+ uint8 *stack_min_addr = os_thread_get_stack_boundary();
+
+ os_mprotect(stack_min_addr, page_size * guard_page_count,
+ MMAP_PROT_READ | MMAP_PROT_WRITE);
+}
+#endif /* end of WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 */
+
+static void
+mask_signals(int how)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGSEGV);
+ sigaddset(&set, SIGBUS);
+ pthread_sigmask(how, &set, NULL);
+}
+
+static os_thread_local_attribute struct sigaction prev_sig_act_SIGSEGV;
+static os_thread_local_attribute struct sigaction prev_sig_act_SIGBUS;
+
+static void
+signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext)
+{
+ void *sig_addr = sig_info->si_addr;
+ struct sigaction *prev_sig_act = NULL;
+
+ mask_signals(SIG_BLOCK);
+
+ /* Try to handle signal with the registered signal handler */
+ if (signal_handler && (sig_num == SIGSEGV || sig_num == SIGBUS)) {
+ signal_handler(sig_addr);
+ }
+
+ if (sig_num == SIGSEGV)
+ prev_sig_act = &prev_sig_act_SIGSEGV;
+ else if (sig_num == SIGBUS)
+ prev_sig_act = &prev_sig_act_SIGBUS;
+
+ /* Forward the signal to next handler if found */
+ if (prev_sig_act && (prev_sig_act->sa_flags & SA_SIGINFO)) {
+ prev_sig_act->sa_sigaction(sig_num, sig_info, sig_ucontext);
+ }
+ else if (prev_sig_act
+ && ((void *)prev_sig_act->sa_sigaction == SIG_DFL
+ || (void *)prev_sig_act->sa_sigaction == SIG_IGN)) {
+ sigaction(sig_num, prev_sig_act, NULL);
+ }
+ /* Output signal info and then crash if signal is unhandled */
+ else {
+ switch (sig_num) {
+ case SIGSEGV:
+ os_printf("unhandled SIGSEGV, si_addr: %p\n", sig_addr);
+ break;
+ case SIGBUS:
+ os_printf("unhandled SIGBUS, si_addr: %p\n", sig_addr);
+ break;
+ default:
+ os_printf("unhandle signal %d, si_addr: %p\n", sig_num,
+ sig_addr);
+ break;
+ }
+
+ abort();
+ }
+}
+
+int
+os_thread_signal_init(os_signal_handler handler)
+{
+ struct sigaction sig_act;
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ stack_t sigalt_stack_info;
+ uint32 map_size = SIG_ALT_STACK_SIZE;
+ uint8 *map_addr;
+#endif
+
+ if (thread_signal_inited)
+ return 0;
+
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ if (!init_stack_guard_pages()) {
+ os_printf("Failed to init stack guard pages\n");
+ return -1;
+ }
+
+ /* Initialize memory for signal alternate stack of current thread */
+ if (!(map_addr = os_mmap(NULL, map_size, MMAP_PROT_READ | MMAP_PROT_WRITE,
+ MMAP_MAP_NONE))) {
+ os_printf("Failed to mmap memory for alternate stack\n");
+ goto fail1;
+ }
+
+ /* Initialize signal alternate stack */
+ memset(map_addr, 0, map_size);
+ sigalt_stack_info.ss_sp = map_addr;
+ sigalt_stack_info.ss_size = map_size;
+ sigalt_stack_info.ss_flags = 0;
+ if (sigaltstack(&sigalt_stack_info, NULL) != 0) {
+ os_printf("Failed to init signal alternate stack\n");
+ goto fail2;
+ }
+#endif
+
+ memset(&prev_sig_act_SIGSEGV, 0, sizeof(struct sigaction));
+ memset(&prev_sig_act_SIGBUS, 0, sizeof(struct sigaction));
+
+ /* Install signal hanlder */
+ sig_act.sa_sigaction = signal_callback;
+ sig_act.sa_flags = SA_SIGINFO | SA_NODEFER;
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ sig_act.sa_flags |= SA_ONSTACK;
+#endif
+ sigemptyset(&sig_act.sa_mask);
+ if (sigaction(SIGSEGV, &sig_act, &prev_sig_act_SIGSEGV) != 0
+ || sigaction(SIGBUS, &sig_act, &prev_sig_act_SIGBUS) != 0) {
+ os_printf("Failed to register signal handler\n");
+ goto fail3;
+ }
+
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ sigalt_stack_base_addr = map_addr;
+#endif
+ signal_handler = handler;
+ thread_signal_inited = true;
+ return 0;
+
+fail3:
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ memset(&sigalt_stack_info, 0, sizeof(stack_t));
+ sigalt_stack_info.ss_flags = SS_DISABLE;
+ sigalt_stack_info.ss_size = map_size;
+ sigaltstack(&sigalt_stack_info, NULL);
+fail2:
+ os_munmap(map_addr, map_size);
+fail1:
+ destroy_stack_guard_pages();
+#endif
+ return -1;
+}
+
+void
+os_thread_signal_destroy()
+{
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ stack_t sigalt_stack_info;
+#endif
+
+ if (!thread_signal_inited)
+ return;
+
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ /* Disable signal alternate stack */
+ memset(&sigalt_stack_info, 0, sizeof(stack_t));
+ sigalt_stack_info.ss_flags = SS_DISABLE;
+ sigalt_stack_info.ss_size = SIG_ALT_STACK_SIZE;
+ sigaltstack(&sigalt_stack_info, NULL);
+
+ os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE);
+
+ destroy_stack_guard_pages();
+#endif
+
+ thread_signal_inited = false;
+}
+
+bool
+os_thread_signal_inited()
+{
+ return thread_signal_inited;
+}
+
+void
+os_signal_unmask()
+{
+ mask_signals(SIG_UNBLOCK);
+}
+
+void
+os_sigreturn()
+{
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+#if defined(__APPLE__)
+#define UC_RESET_ALT_STACK 0x80000000
+ extern int __sigreturn(void *, int);
+
+ /* It's necessary to call __sigreturn to restore the sigaltstack state
+ after exiting the signal handler. */
+ __sigreturn(NULL, UC_RESET_ALT_STACK);
+#endif
+#endif
+}
+#endif /* end of OS_ENABLE_HW_BOUND_CHECK */