|
@@ -3,155 +3,499 @@
|
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-#ifndef _GNU_SOURCE
|
|
|
|
|
-#define _GNU_SOURCE
|
|
|
|
|
-#endif
|
|
|
|
|
#include "platform_api_vmcore.h"
|
|
#include "platform_api_vmcore.h"
|
|
|
#include "platform_api_extension.h"
|
|
#include "platform_api_extension.h"
|
|
|
|
|
|
|
|
-typedef struct {
|
|
|
|
|
- thread_start_routine_t start;
|
|
|
|
|
- void* stack;
|
|
|
|
|
- uint32 stack_size;
|
|
|
|
|
- void* arg;
|
|
|
|
|
-} thread_wrapper_arg;
|
|
|
|
|
-
|
|
|
|
|
-static void *os_thread_wrapper(void *arg)
|
|
|
|
|
|
|
+#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;
|
|
|
|
|
+} os_thread_data;
|
|
|
|
|
+
|
|
|
|
|
+static bool is_thread_sys_inited = false;
|
|
|
|
|
+
|
|
|
|
|
+/* Thread data of supervisor thread */
|
|
|
|
|
+static os_thread_data supervisor_thread_data;
|
|
|
|
|
+
|
|
|
|
|
+/* Thread data key */
|
|
|
|
|
+static DWORD thread_data_key;
|
|
|
|
|
+
|
|
|
|
|
+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()
|
|
|
{
|
|
{
|
|
|
- thread_wrapper_arg * targ = arg;
|
|
|
|
|
- thread_start_routine_t start_func = targ->start;
|
|
|
|
|
- void *thread_arg = targ->arg;
|
|
|
|
|
- os_printf("THREAD CREATED %p\n", &targ);
|
|
|
|
|
- targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff);
|
|
|
|
|
- BH_FREE(targ);
|
|
|
|
|
- start_func(thread_arg);
|
|
|
|
|
- return NULL;
|
|
|
|
|
|
|
+ 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;
|
|
|
|
|
+
|
|
|
|
|
+ is_thread_sys_inited = true;
|
|
|
|
|
+ return BHT_OK;
|
|
|
|
|
+
|
|
|
|
|
+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;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
|
|
|
|
|
- void *arg, unsigned int stack_size, int prio)
|
|
|
|
|
|
|
+void
|
|
|
|
|
+os_thread_sys_destroy()
|
|
|
{
|
|
{
|
|
|
- return BHT_ERROR;
|
|
|
|
|
|
|
+ if (is_thread_sys_inited) {
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
|
|
|
|
|
- unsigned int stack_size)
|
|
|
|
|
|
|
+static os_thread_data *
|
|
|
|
|
+thread_data_current()
|
|
|
{
|
|
{
|
|
|
- return os_thread_create_with_prio(tid, start, arg, stack_size,
|
|
|
|
|
- BH_THREAD_DEFAULT_PRIORITY);
|
|
|
|
|
|
|
+ return (os_thread_data *)TlsGetValue(thread_data_key);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-korp_tid os_self_thread()
|
|
|
|
|
|
|
+static void
|
|
|
|
|
+os_thread_cleanup(void *retval)
|
|
|
{
|
|
{
|
|
|
- return NULL;
|
|
|
|
|
|
|
+ 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 = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ os_mutex_unlock(&thread_data->wait_lock);
|
|
|
|
|
+
|
|
|
|
|
+ /* Destroy resources */
|
|
|
|
|
+ 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);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_mutex_init(korp_mutex *mutex)
|
|
|
|
|
|
|
+static unsigned
|
|
|
|
|
+os_thread_wrapper(void *arg)
|
|
|
{
|
|
{
|
|
|
- return BHT_OK;
|
|
|
|
|
|
|
+ os_thread_data *thread_data = arg;
|
|
|
|
|
+ os_thread_data *parent = thread_data->parent;
|
|
|
|
|
+ void *retval;
|
|
|
|
|
+ bool result;
|
|
|
|
|
+
|
|
|
|
|
+ os_printf("THREAD CREATED %p\n", thread_data);
|
|
|
|
|
+
|
|
|
|
|
+ os_mutex_lock(&parent->wait_lock);
|
|
|
|
|
+ thread_data->thread_id = GetCurrentThreadId();
|
|
|
|
|
+ result = TlsSetValue(thread_data_key, thread_data);
|
|
|
|
|
+ /* 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_recursive_mutex_init(korp_mutex *mutex)
|
|
|
|
|
|
|
+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;
|
|
|
|
|
+ }
|
|
|
|
|
+ /* 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;
|
|
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_mutex_destroy(korp_mutex *mutex)
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
|
|
|
|
|
+ unsigned int stack_size)
|
|
|
{
|
|
{
|
|
|
- return BHT_OK;
|
|
|
|
|
|
|
+ return os_thread_create_with_prio(tid, start, arg, stack_size,
|
|
|
|
|
+ BH_THREAD_DEFAULT_PRIORITY);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_mutex_lock(korp_mutex *mutex)
|
|
|
|
|
|
|
+korp_tid
|
|
|
|
|
+os_self_thread()
|
|
|
{
|
|
{
|
|
|
- return BHT_ERROR;
|
|
|
|
|
|
|
+ return (korp_tid)TlsGetValue(thread_data_key);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_mutex_unlock(korp_mutex *mutex)
|
|
|
|
|
|
|
+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_wait_list)
|
|
|
|
|
+ thread_data->thread_wait_list = &curr_thread_data->wait_node;
|
|
|
|
|
+ else {
|
|
|
|
|
+ /* Add to end of waiting list */
|
|
|
|
|
+ os_thread_wait_node *p = thread_data->thread_wait_list;
|
|
|
|
|
+ while (p->next)
|
|
|
|
|
+ p = p->next;
|
|
|
|
|
+ p->next = &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;
|
|
return BHT_OK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_cond_init(korp_cond *cond)
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_thread_detach(korp_tid thread)
|
|
|
{
|
|
{
|
|
|
|
|
+ /* Do nothing */
|
|
|
return BHT_OK;
|
|
return BHT_OK;
|
|
|
|
|
+ (void)thread;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_cond_destroy(korp_cond *cond)
|
|
|
|
|
|
|
+void
|
|
|
|
|
+os_thread_exit(void *retval)
|
|
|
{
|
|
{
|
|
|
- return BHT_OK;
|
|
|
|
|
|
|
+ os_thread_cleanup(retval);
|
|
|
|
|
+ _endthreadex(0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_cond_wait(korp_cond *cond, korp_mutex *mutex)
|
|
|
|
|
|
|
+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;
|
|
return BHT_OK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_sem_wait(korp_sem *sem)
|
|
|
|
|
+{
|
|
|
|
|
+ DWORD ret;
|
|
|
|
|
+
|
|
|
|
|
+ bh_assert(sem);
|
|
|
|
|
|
|
|
-int gettimeofday(struct timeval * tp, struct timezone * tzp)
|
|
|
|
|
|
|
+ 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)
|
|
|
{
|
|
{
|
|
|
- /* Note: some broken versions only have 8 trailing zero's,
|
|
|
|
|
- the correct epoch has 9 trailing zero's
|
|
|
|
|
- This magic number is the number of 100 nanosecond intervals
|
|
|
|
|
- since January 1, 1601 (UTC) until 00:00:00 January 1, 1970 */
|
|
|
|
|
- static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
|
|
|
|
|
|
|
+ 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");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- SYSTEMTIME system_time;
|
|
|
|
|
- FILETIME file_time;
|
|
|
|
|
- uint64_t time;
|
|
|
|
|
|
|
+ ret = WaitForSingleObject(*sem, mseconds);
|
|
|
|
|
|
|
|
- GetSystemTime(&system_time);
|
|
|
|
|
- SystemTimeToFileTime(&system_time, &file_time);
|
|
|
|
|
- time = ((uint64_t)file_time.dwLowDateTime);
|
|
|
|
|
- time += ((uint64_t)file_time.dwHighDateTime) << 32;
|
|
|
|
|
|
|
+ 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;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- tp->tv_sec = (long)((time - EPOCH) / 10000000L);
|
|
|
|
|
- tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_sem_signal(korp_sem *sem)
|
|
|
|
|
+{
|
|
|
|
|
+ bh_assert(sem);
|
|
|
|
|
+ return ReleaseSemaphore(*sem, 1, NULL) != FALSE
|
|
|
|
|
+ ? BHT_OK: BHT_ERROR;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_mutex_init(korp_mutex *mutex)
|
|
|
|
|
+{
|
|
|
|
|
+ bh_assert(mutex);
|
|
|
|
|
+ *mutex = CreateMutex(NULL, FALSE, NULL);
|
|
|
|
|
+ return (*mutex != NULL) ? BHT_OK : BHT_ERROR;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void msec_nsec_to_abstime(struct timespec *ts, int usec)
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_recursive_mutex_init(korp_mutex *mutex)
|
|
|
{
|
|
{
|
|
|
- struct timeval tv;
|
|
|
|
|
|
|
+ bh_assert(mutex);
|
|
|
|
|
+ *mutex = CreateMutex(NULL, FALSE, NULL);
|
|
|
|
|
+ return (*mutex != NULL) ? BHT_OK : BHT_ERROR;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- gettimeofday(&tv, NULL);
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_mutex_destroy(korp_mutex *mutex)
|
|
|
|
|
+{
|
|
|
|
|
+ assert(mutex);
|
|
|
|
|
+ return CloseHandle(*mutex) ? BHT_OK : BHT_ERROR;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- ts->tv_sec = (long int)(tv.tv_sec + usec / 1000000);
|
|
|
|
|
- ts->tv_nsec = (long int)(tv.tv_usec * 1000 + (usec % 1000000) * 1000);
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_mutex_lock(korp_mutex *mutex)
|
|
|
|
|
+{
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
|
|
- if (ts->tv_nsec >= 1000000000L) {
|
|
|
|
|
- ts->tv_sec++;
|
|
|
|
|
- ts->tv_nsec -= 1000000000L;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ assert(mutex);
|
|
|
|
|
+ ret = WaitForSingleObject(*mutex, INFINITE);
|
|
|
|
|
+ return ret != WAIT_FAILED ? BHT_OK : BHT_ERROR;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds)
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_mutex_unlock(korp_mutex *mutex)
|
|
|
{
|
|
{
|
|
|
- return BHT_OK;
|
|
|
|
|
|
|
+ bh_assert(mutex);
|
|
|
|
|
+ return ReleaseMutex(*mutex) ? BHT_OK : BHT_ERROR;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_cond_signal(korp_cond *cond)
|
|
|
|
|
|
|
+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 = NULL;
|
|
|
return BHT_OK;
|
|
return BHT_OK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_thread_join(korp_tid thread, void **value_ptr)
|
|
|
|
|
|
|
+int
|
|
|
|
|
+os_cond_destroy(korp_cond *cond)
|
|
|
{
|
|
{
|
|
|
|
|
+ bh_assert(cond);
|
|
|
|
|
+ os_mutex_destroy(&cond->wait_list_lock);
|
|
|
return BHT_OK;
|
|
return BHT_OK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int os_thread_detach(korp_tid thread)
|
|
|
|
|
|
|
+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)
|
|
|
|
|
+ cond->thread_wait_list = node;
|
|
|
|
|
+ else {
|
|
|
|
|
+ /* Add to end of wait list */
|
|
|
|
|
+ os_thread_wait_node *p = cond->thread_wait_list;
|
|
|
|
|
+ while (p->next)
|
|
|
|
|
+ p = p->next;
|
|
|
|
|
+ p->next = node;
|
|
|
|
|
+ }
|
|
|
|
|
+ os_mutex_unlock(&cond->wait_list_lock);
|
|
|
|
|
+
|
|
|
|
|
+ /* Unlock mutex, wait sem and lock mutex again */
|
|
|
|
|
+ os_mutex_unlock(mutex);
|
|
|
|
|
+ if (timed)
|
|
|
|
|
+ os_sem_reltimed_wait(&node->sem, useconds);
|
|
|
|
|
+ else
|
|
|
|
|
+ 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;
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
|
|
+ os_mutex_unlock(&cond->wait_list_lock);
|
|
|
|
|
+
|
|
|
return BHT_OK;
|
|
return BHT_OK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void os_thread_exit(void *retval)
|
|
|
|
|
|
|
+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;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static os_thread_local_attribute uint8 *thread_stack_boundary = NULL;
|
|
static os_thread_local_attribute uint8 *thread_stack_boundary = NULL;
|
|
|
|
|
|
|
|
-uint8 *os_thread_get_stack_boundary()
|
|
|
|
|
|
|
+uint8 *
|
|
|
|
|
+os_thread_get_stack_boundary()
|
|
|
{
|
|
{
|
|
|
ULONG_PTR low_limit = 0, high_limit = 0;
|
|
ULONG_PTR low_limit = 0, high_limit = 0;
|
|
|
uint32 page_size;
|
|
uint32 page_size;
|
|
@@ -167,10 +511,21 @@ uint8 *os_thread_get_stack_boundary()
|
|
|
return thread_stack_boundary;
|
|
return thread_stack_boundary;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static os_thread_local_attribute bool stack_guard_pages_inited = false;
|
|
|
|
|
+
|
|
|
bool
|
|
bool
|
|
|
os_thread_init_stack_guard_pages()
|
|
os_thread_init_stack_guard_pages()
|
|
|
{
|
|
{
|
|
|
- return true;
|
|
|
|
|
|
|
+ ULONG StackSizeInBytes = 16 * 1024;
|
|
|
|
|
+ bool ret;
|
|
|
|
|
+
|
|
|
|
|
+ if (stack_guard_pages_inited)
|
|
|
|
|
+ return true;
|
|
|
|
|
+
|
|
|
|
|
+ ret = SetThreadStackGuarantee(&StackSizeInBytes);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ stack_guard_pages_inited = true;
|
|
|
|
|
+ return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
void
|