summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c')
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c750
1 files changed, 750 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c
new file mode 100644
index 000000000..09cf0c63f
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "platform_api_vmcore.h"
+#include "platform_api_extension.h"
+
+#define bh_assert(v) assert(v)
+
+#define BH_SEM_COUNT_MAX 0xFFFF
+
+struct os_thread_data;
+
+typedef struct os_thread_wait_node {
+ korp_sem sem;
+ void *retval;
+ os_thread_wait_list next;
+} os_thread_wait_node;
+
+typedef struct os_thread_data {
+ /* Next thread data */
+ struct os_thread_data *next;
+ /* Thread data of parent thread */
+ struct os_thread_data *parent;
+ /* Thread Id */
+ DWORD thread_id;
+ /* Thread start routine */
+ thread_start_routine_t start_routine;
+ /* Thread start routine argument */
+ void *arg;
+ /* Wait node of current thread */
+ os_thread_wait_node wait_node;
+ /* Wait cond */
+ korp_cond wait_cond;
+ /* Wait lock */
+ korp_mutex wait_lock;
+ /* Waiting list of other threads who are joining this thread */
+ os_thread_wait_list thread_wait_list;
+ /* End node of the waiting list */
+ os_thread_wait_node *thread_wait_list_end;
+ /* Whether the thread has exited */
+ bool thread_exited;
+ /* Thread return value */
+ void *thread_retval;
+} os_thread_data;
+
+static bool is_thread_sys_inited = false;
+
+/* Thread data of supervisor thread */
+static os_thread_data supervisor_thread_data;
+
+/* Thread data list lock */
+static korp_mutex thread_data_list_lock;
+
+/* Thread data key */
+static DWORD thread_data_key;
+
+/* The GetCurrentThreadStackLimits API from "kernel32" */
+static void(WINAPI *GetCurrentThreadStackLimits_Kernel32)(PULONG_PTR,
+ PULONG_PTR) = NULL;
+
+int
+os_sem_init(korp_sem *sem);
+int
+os_sem_destroy(korp_sem *sem);
+int
+os_sem_wait(korp_sem *sem);
+int
+os_sem_reltimed_wait(korp_sem *sem, uint64 useconds);
+int
+os_sem_signal(korp_sem *sem);
+
+int
+os_thread_sys_init()
+{
+ HMODULE module;
+
+ if (is_thread_sys_inited)
+ return BHT_OK;
+
+ if ((thread_data_key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ return BHT_ERROR;
+
+ /* Initialize supervisor thread data */
+ memset(&supervisor_thread_data, 0, sizeof(os_thread_data));
+
+ supervisor_thread_data.thread_id = GetCurrentThreadId();
+
+ if (os_sem_init(&supervisor_thread_data.wait_node.sem) != BHT_OK)
+ goto fail1;
+
+ if (os_mutex_init(&supervisor_thread_data.wait_lock) != BHT_OK)
+ goto fail2;
+
+ if (os_cond_init(&supervisor_thread_data.wait_cond) != BHT_OK)
+ goto fail3;
+
+ if (!TlsSetValue(thread_data_key, &supervisor_thread_data))
+ goto fail4;
+
+ if (os_mutex_init(&thread_data_list_lock) != BHT_OK)
+ goto fail5;
+
+ if ((module = GetModuleHandle((LPCTSTR) "kernel32"))) {
+ *(void **)&GetCurrentThreadStackLimits_Kernel32 =
+ GetProcAddress(module, "GetCurrentThreadStackLimits");
+ }
+
+ is_thread_sys_inited = true;
+ return BHT_OK;
+
+fail5:
+ TlsSetValue(thread_data_key, NULL);
+fail4:
+ os_cond_destroy(&supervisor_thread_data.wait_cond);
+fail3:
+ os_mutex_destroy(&supervisor_thread_data.wait_lock);
+fail2:
+ os_sem_destroy(&supervisor_thread_data.wait_node.sem);
+fail1:
+ TlsFree(thread_data_key);
+ return BHT_ERROR;
+}
+
+void
+os_thread_sys_destroy()
+{
+ if (is_thread_sys_inited) {
+ os_thread_data *thread_data, *thread_data_next;
+
+ thread_data = supervisor_thread_data.next;
+ while (thread_data) {
+ thread_data_next = thread_data->next;
+
+ /* Destroy resources of thread data */
+ os_cond_destroy(&thread_data->wait_cond);
+ os_sem_destroy(&thread_data->wait_node.sem);
+ os_mutex_destroy(&thread_data->wait_lock);
+ BH_FREE(thread_data);
+
+ thread_data = thread_data_next;
+ }
+
+ os_mutex_destroy(&thread_data_list_lock);
+ os_cond_destroy(&supervisor_thread_data.wait_cond);
+ os_mutex_destroy(&supervisor_thread_data.wait_lock);
+ os_sem_destroy(&supervisor_thread_data.wait_node.sem);
+ memset(&supervisor_thread_data, 0, sizeof(os_thread_data));
+ TlsFree(thread_data_key);
+ thread_data_key = 0;
+ is_thread_sys_inited = false;
+ }
+}
+
+static os_thread_data *
+thread_data_current()
+{
+ return (os_thread_data *)TlsGetValue(thread_data_key);
+}
+
+static void
+os_thread_cleanup(void *retval)
+{
+ os_thread_data *thread_data = thread_data_current();
+
+ bh_assert(thread_data != NULL);
+
+ os_mutex_lock(&thread_data->wait_lock);
+ if (thread_data->thread_wait_list) {
+ /* Signal each joining thread */
+ os_thread_wait_list head = thread_data->thread_wait_list;
+ while (head) {
+ os_thread_wait_list next = head->next;
+ head->retval = retval;
+ os_sem_signal(&head->sem);
+ head = next;
+ }
+ thread_data->thread_wait_list = thread_data->thread_wait_list_end =
+ NULL;
+ }
+ /* Set thread status and thread return value */
+ thread_data->thread_exited = true;
+ thread_data->thread_retval = retval;
+ os_mutex_unlock(&thread_data->wait_lock);
+}
+
+static unsigned __stdcall os_thread_wrapper(void *arg)
+{
+ os_thread_data *thread_data = arg;
+ os_thread_data *parent = thread_data->parent;
+ void *retval;
+ bool result;
+
+#if 0
+ os_printf("THREAD CREATED %p\n", thread_data);
+#endif
+
+ os_mutex_lock(&parent->wait_lock);
+ thread_data->thread_id = GetCurrentThreadId();
+ result = TlsSetValue(thread_data_key, thread_data);
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ if (result)
+ result = os_thread_signal_init() == 0 ? true : false;
+#endif
+ /* Notify parent thread */
+ os_cond_signal(&parent->wait_cond);
+ os_mutex_unlock(&parent->wait_lock);
+
+ if (!result)
+ return -1;
+
+ retval = thread_data->start_routine(thread_data->arg);
+
+ os_thread_cleanup(retval);
+ return 0;
+}
+
+int
+os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start,
+ void *arg, unsigned int stack_size, int prio)
+{
+ os_thread_data *parent = thread_data_current();
+ os_thread_data *thread_data;
+
+ if (!p_tid || !start)
+ return BHT_ERROR;
+
+ if (stack_size < BH_APPLET_PRESERVED_STACK_SIZE)
+ stack_size = BH_APPLET_PRESERVED_STACK_SIZE;
+
+ if (!(thread_data = BH_MALLOC(sizeof(os_thread_data))))
+ return BHT_ERROR;
+
+ memset(thread_data, 0, sizeof(os_thread_data));
+ thread_data->parent = parent;
+ thread_data->start_routine = start;
+ thread_data->arg = arg;
+
+ if (os_sem_init(&thread_data->wait_node.sem) != BHT_OK)
+ goto fail1;
+
+ if (os_mutex_init(&thread_data->wait_lock) != BHT_OK)
+ goto fail2;
+
+ if (os_cond_init(&thread_data->wait_cond) != BHT_OK)
+ goto fail3;
+
+ os_mutex_lock(&parent->wait_lock);
+ if (!_beginthreadex(NULL, stack_size, os_thread_wrapper, thread_data, 0,
+ NULL)) {
+ os_mutex_unlock(&parent->wait_lock);
+ goto fail4;
+ }
+
+ /* Add thread data into thread data list */
+ os_mutex_lock(&thread_data_list_lock);
+ thread_data->next = supervisor_thread_data.next;
+ supervisor_thread_data.next = thread_data;
+ os_mutex_unlock(&thread_data_list_lock);
+
+ /* Wait for the thread routine to set thread_data's tid
+ and add thread_data to thread data list */
+ os_cond_wait(&parent->wait_cond, &parent->wait_lock);
+ os_mutex_unlock(&parent->wait_lock);
+
+ *p_tid = (korp_tid)thread_data;
+ return BHT_OK;
+
+fail4:
+ os_cond_destroy(&thread_data->wait_cond);
+fail3:
+ os_mutex_destroy(&thread_data->wait_lock);
+fail2:
+ os_sem_destroy(&thread_data->wait_node.sem);
+fail1:
+ BH_FREE(thread_data);
+ return BHT_ERROR;
+}
+
+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)TlsGetValue(thread_data_key);
+}
+
+int
+os_thread_join(korp_tid thread, void **p_retval)
+{
+ os_thread_data *thread_data, *curr_thread_data;
+
+ /* Get thread data of current thread */
+ curr_thread_data = thread_data_current();
+ curr_thread_data->wait_node.next = NULL;
+
+ /* Get thread data of thread to join */
+ thread_data = (os_thread_data *)thread;
+ bh_assert(thread_data);
+
+ os_mutex_lock(&thread_data->wait_lock);
+
+ if (thread_data->thread_exited) {
+ /* Thread has exited */
+ if (p_retval)
+ *p_retval = thread_data->thread_retval;
+ os_mutex_unlock(&thread_data->wait_lock);
+ return BHT_OK;
+ }
+
+ /* Thread is running */
+ if (!thread_data->thread_wait_list) { /* Waiting list is empty */
+ thread_data->thread_wait_list = thread_data->thread_wait_list_end =
+ &curr_thread_data->wait_node;
+ }
+ else { /* Waiting list isn't empty */
+ /* Add to end of waiting list */
+ thread_data->thread_wait_list_end->next = &curr_thread_data->wait_node;
+ thread_data->thread_wait_list_end = &curr_thread_data->wait_node;
+ }
+
+ os_mutex_unlock(&thread_data->wait_lock);
+
+ /* Wait the sem */
+ os_sem_wait(&curr_thread_data->wait_node.sem);
+ if (p_retval)
+ *p_retval = curr_thread_data->wait_node.retval;
+ return BHT_OK;
+}
+
+int
+os_thread_detach(korp_tid thread)
+{
+ /* Do nothing */
+ return BHT_OK;
+ (void)thread;
+}
+
+void
+os_thread_exit(void *retval)
+{
+ os_thread_cleanup(retval);
+ _endthreadex(0);
+}
+
+int
+os_thread_env_init()
+{
+ os_thread_data *thread_data = TlsGetValue(thread_data_key);
+
+ if (thread_data)
+ /* Already created */
+ return BHT_OK;
+
+ if (!(thread_data = BH_MALLOC(sizeof(os_thread_data))))
+ return BHT_ERROR;
+
+ memset(thread_data, 0, sizeof(os_thread_data));
+ thread_data->thread_id = GetCurrentThreadId();
+
+ if (os_sem_init(&thread_data->wait_node.sem) != BHT_OK)
+ goto fail1;
+
+ if (os_mutex_init(&thread_data->wait_lock) != BHT_OK)
+ goto fail2;
+
+ if (os_cond_init(&thread_data->wait_cond) != BHT_OK)
+ goto fail3;
+
+ if (!TlsSetValue(thread_data_key, thread_data))
+ goto fail4;
+
+ return BHT_OK;
+
+fail4:
+ os_cond_destroy(&thread_data->wait_cond);
+fail3:
+ os_mutex_destroy(&thread_data->wait_lock);
+fail2:
+ os_sem_destroy(&thread_data->wait_node.sem);
+fail1:
+ BH_FREE(thread_data);
+ return BHT_ERROR;
+}
+
+void
+os_thread_env_destroy()
+{
+ os_thread_data *thread_data = TlsGetValue(thread_data_key);
+
+ /* Note that supervisor_thread_data's resources will be destroyed
+ by os_thread_sys_destroy() */
+ if (thread_data && thread_data != &supervisor_thread_data) {
+ TlsSetValue(thread_data_key, NULL);
+ os_cond_destroy(&thread_data->wait_cond);
+ os_mutex_destroy(&thread_data->wait_lock);
+ os_sem_destroy(&thread_data->wait_node.sem);
+ BH_FREE(thread_data);
+ }
+}
+
+bool
+os_thread_env_inited()
+{
+ os_thread_data *thread_data = TlsGetValue(thread_data_key);
+ return thread_data ? true : false;
+}
+
+int
+os_sem_init(korp_sem *sem)
+{
+ bh_assert(sem);
+ *sem = CreateSemaphore(NULL, 0, BH_SEM_COUNT_MAX, NULL);
+ return (*sem != NULL) ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_sem_destroy(korp_sem *sem)
+{
+ bh_assert(sem);
+ CloseHandle(*sem);
+ return BHT_OK;
+}
+
+int
+os_sem_wait(korp_sem *sem)
+{
+ DWORD ret;
+
+ bh_assert(sem);
+
+ ret = WaitForSingleObject(*sem, INFINITE);
+
+ if (ret == WAIT_OBJECT_0)
+ return BHT_OK;
+ else if (ret == WAIT_TIMEOUT)
+ return (int)WAIT_TIMEOUT;
+ else /* WAIT_FAILED or others */
+ return BHT_ERROR;
+}
+
+int
+os_sem_reltimed_wait(korp_sem *sem, uint64 useconds)
+{
+ uint64 mseconds_64;
+ DWORD ret, mseconds;
+
+ bh_assert(sem);
+
+ if (useconds == BHT_WAIT_FOREVER)
+ mseconds = INFINITE;
+ else {
+ mseconds_64 = useconds / 1000;
+
+ if (mseconds_64 < (uint64)(UINT32_MAX - 1)) {
+ mseconds = (uint32)mseconds_64;
+ }
+ else {
+ mseconds = UINT32_MAX - 1;
+ os_printf("Warning: os_sem_reltimed_wait exceeds limit, "
+ "set to max timeout instead\n");
+ }
+ }
+
+ ret = WaitForSingleObject(*sem, mseconds);
+
+ if (ret == WAIT_OBJECT_0)
+ return BHT_OK;
+ else if (ret == WAIT_TIMEOUT)
+ return (int)WAIT_TIMEOUT;
+ else /* WAIT_FAILED or others */
+ return BHT_ERROR;
+}
+
+int
+os_sem_signal(korp_sem *sem)
+{
+ bh_assert(sem);
+ return ReleaseSemaphore(*sem, 1, NULL) != FALSE ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_mutex_init(korp_mutex *mutex)
+{
+ bh_assert(mutex);
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ return (*mutex != NULL) ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_recursive_mutex_init(korp_mutex *mutex)
+{
+ bh_assert(mutex);
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ return (*mutex != NULL) ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_mutex_destroy(korp_mutex *mutex)
+{
+ assert(mutex);
+ return CloseHandle(*mutex) ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_mutex_lock(korp_mutex *mutex)
+{
+ int ret;
+
+ assert(mutex);
+
+ if (*mutex == NULL) { /* static initializer? */
+ HANDLE p = CreateMutex(NULL, FALSE, NULL);
+
+ if (!p) {
+ return BHT_ERROR;
+ }
+
+ if (InterlockedCompareExchangePointer((PVOID *)mutex, (PVOID)p, NULL)
+ != NULL) {
+ /* lock has been created by other threads */
+ CloseHandle(p);
+ }
+ }
+
+ ret = WaitForSingleObject(*mutex, INFINITE);
+ return ret != WAIT_FAILED ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_mutex_unlock(korp_mutex *mutex)
+{
+ bh_assert(mutex);
+ return ReleaseMutex(*mutex) ? BHT_OK : BHT_ERROR;
+}
+
+int
+os_cond_init(korp_cond *cond)
+{
+ bh_assert(cond);
+ if (os_mutex_init(&cond->wait_list_lock) != BHT_OK)
+ return BHT_ERROR;
+
+ cond->thread_wait_list = cond->thread_wait_list_end = NULL;
+ return BHT_OK;
+}
+
+int
+os_cond_destroy(korp_cond *cond)
+{
+ bh_assert(cond);
+ os_mutex_destroy(&cond->wait_list_lock);
+ return BHT_OK;
+}
+
+static int
+os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed,
+ uint64 useconds)
+{
+ os_thread_wait_node *node = &thread_data_current()->wait_node;
+
+ node->next = NULL;
+
+ bh_assert(cond);
+ bh_assert(mutex);
+ os_mutex_lock(&cond->wait_list_lock);
+ if (!cond->thread_wait_list) { /* Waiting list is empty */
+ cond->thread_wait_list = cond->thread_wait_list_end = node;
+ }
+ else { /* Waiting list isn't empty */
+ /* Add to end of wait list */
+ cond->thread_wait_list_end->next = node;
+ cond->thread_wait_list_end = node;
+ }
+ os_mutex_unlock(&cond->wait_list_lock);
+
+ /* Unlock mutex, wait sem and lock mutex again */
+ os_mutex_unlock(mutex);
+ int wait_result;
+ if (timed)
+ wait_result = os_sem_reltimed_wait(&node->sem, useconds);
+ else
+ wait_result = os_sem_wait(&node->sem);
+ os_mutex_lock(mutex);
+
+ /* Remove wait node from wait list */
+ os_mutex_lock(&cond->wait_list_lock);
+ if (cond->thread_wait_list == node) {
+ cond->thread_wait_list = node->next;
+
+ if (cond->thread_wait_list_end == node) {
+ bh_assert(node->next == NULL);
+ cond->thread_wait_list_end = NULL;
+ }
+ }
+ else {
+ /* Remove from the wait list */
+ os_thread_wait_node *p = cond->thread_wait_list;
+ while (p->next != node)
+ p = p->next;
+ p->next = node->next;
+
+ if (cond->thread_wait_list_end == node) {
+ cond->thread_wait_list_end = p;
+ }
+ }
+ os_mutex_unlock(&cond->wait_list_lock);
+
+ return wait_result;
+}
+
+int
+os_cond_wait(korp_cond *cond, korp_mutex *mutex)
+{
+ return os_cond_wait_internal(cond, mutex, false, 0);
+}
+
+int
+os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds)
+{
+ if (useconds == BHT_WAIT_FOREVER) {
+ return os_cond_wait_internal(cond, mutex, false, 0);
+ }
+ else {
+ return os_cond_wait_internal(cond, mutex, true, useconds);
+ }
+}
+
+int
+os_cond_signal(korp_cond *cond)
+{
+ /* Signal the head wait node of wait list */
+ os_mutex_lock(&cond->wait_list_lock);
+ if (cond->thread_wait_list)
+ os_sem_signal(&cond->thread_wait_list->sem);
+ os_mutex_unlock(&cond->wait_list_lock);
+
+ return BHT_OK;
+}
+
+int
+os_cond_broadcast(korp_cond *cond)
+{
+ /* Signal all of the wait node of wait list */
+ os_mutex_lock(&cond->wait_list_lock);
+ if (cond->thread_wait_list) {
+ os_thread_wait_node *p = cond->thread_wait_list;
+ while (p) {
+ os_sem_signal(&p->sem);
+ p = p->next;
+ }
+ }
+
+ os_mutex_unlock(&cond->wait_list_lock);
+
+ return BHT_OK;
+}
+
+static os_thread_local_attribute uint8 *thread_stack_boundary = NULL;
+
+static ULONG
+GetCurrentThreadStackLimits_Win7(PULONG_PTR p_low_limit,
+ PULONG_PTR p_high_limit)
+{
+ MEMORY_BASIC_INFORMATION mbi;
+ NT_TIB *tib = (NT_TIB *)NtCurrentTeb();
+
+ if (!tib) {
+ os_printf("warning: NtCurrentTeb() failed\n");
+ return -1;
+ }
+
+ *p_high_limit = (ULONG_PTR)tib->StackBase;
+
+ if (VirtualQuery(tib->StackLimit, &mbi, sizeof(mbi))) {
+ *p_low_limit = (ULONG_PTR)mbi.AllocationBase;
+ return 0;
+ }
+
+ os_printf("warning: VirtualQuery() failed\n");
+ return GetLastError();
+}
+
+uint8 *
+os_thread_get_stack_boundary()
+{
+ ULONG_PTR low_limit = 0, high_limit = 0;
+ uint32 page_size;
+
+ if (thread_stack_boundary)
+ return thread_stack_boundary;
+
+ page_size = os_getpagesize();
+ if (GetCurrentThreadStackLimits_Kernel32) {
+ GetCurrentThreadStackLimits_Kernel32(&low_limit, &high_limit);
+ }
+ else {
+ if (0 != GetCurrentThreadStackLimits_Win7(&low_limit, &high_limit))
+ return NULL;
+ }
+
+ /* 4 pages are set unaccessible by system, we reserved
+ one more page at least for safety */
+ thread_stack_boundary = (uint8 *)(uintptr_t)low_limit + page_size * 5;
+ return thread_stack_boundary;
+}
+
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+static os_thread_local_attribute bool thread_signal_inited = false;
+
+int
+os_thread_signal_init()
+{
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ ULONG StackSizeInBytes = 16 * 1024;
+#endif
+ bool ret;
+
+ if (thread_signal_inited)
+ return 0;
+
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+ ret = SetThreadStackGuarantee(&StackSizeInBytes);
+#else
+ ret = true;
+#endif
+ if (ret)
+ thread_signal_inited = true;
+ return ret ? 0 : -1;
+}
+
+void
+os_thread_signal_destroy()
+{
+ /* Do nothing */
+}
+
+bool
+os_thread_signal_inited()
+{
+ return thread_signal_inited;
+}
+#endif