diff options
Diffstat (limited to 'osdep')
-rw-r--r-- | osdep/win32/include/pthread.h | 11 | ||||
-rw-r--r-- | osdep/win32/pthread.c | 126 |
2 files changed, 89 insertions, 48 deletions
diff --git a/osdep/win32/include/pthread.h b/osdep/win32/include/pthread.h index 271cae0f0a..5157b8e342 100644 --- a/osdep/win32/include/pthread.h +++ b/osdep/win32/include/pthread.h @@ -28,7 +28,6 @@ #define pthread_mutex_unlock m_pthread_mutex_unlock #define pthread_cond_timedwait m_pthread_cond_timedwait #define pthread_cond_wait m_pthread_cond_wait -#define pthread_self m_pthread_self #define pthread_exit m_pthread_exit #define pthread_join m_pthread_join #define pthread_detach m_pthread_detach @@ -80,15 +79,11 @@ int pthread_cond_timedwait(pthread_cond_t *restrict cond, int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); -// Unusual, but allowed by POSIX. -typedef struct { - DWORD id; - struct m_thread_info *info; -} pthread_t; +#define pthread_t DWORD -#define pthread_equal(a, b) ((a).id == (b).id) +#define pthread_equal(a, b) ((a) == (b)) +#define pthread_self() (GetCurrentThreadId()) -pthread_t pthread_self(void); void pthread_exit(void *retval); int pthread_join(pthread_t thread, void **retval); int pthread_detach(pthread_t thread); diff --git a/osdep/win32/pthread.c b/osdep/win32/pthread.c index 57a9d85810..465ac94568 100644 --- a/osdep/win32/pthread.c +++ b/osdep/win32/pthread.c @@ -20,6 +20,7 @@ #include <stdint.h> #include <errno.h> #include <sys/time.h> +#include <assert.h> int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { @@ -113,46 +114,76 @@ int pthread_cond_wait(pthread_cond_t *restrict cond, return cond_wait(cond, mutex, INFINITE); } +static pthread_mutex_t pthread_table_lock = PTHREAD_MUTEX_INITIALIZER; +static struct m_thread_info *pthread_table; +size_t pthread_table_num; + struct m_thread_info { + DWORD id; HANDLE handle; void *(*user_fn)(void *); void *user_arg; void *res; }; -// Assuming __thread maps to __declspec(thread) -static __thread struct m_thread_info *self; +static struct m_thread_info *find_thread_info(DWORD id) +{ + for (int n = 0; n < pthread_table_num; n++) { + if (id == pthread_table[n].id) + return &pthread_table[n]; + } + return NULL; +} -pthread_t pthread_self(void) +static void remove_thread_info(struct m_thread_info *info) { - return (pthread_t){GetCurrentThreadId(), self}; + assert(pthread_table_num); + assert(info >= &pthread_table[0] && info < &pthread_table[pthread_table_num]); + + pthread_table[info - pthread_table] = pthread_table[pthread_table_num - 1]; + pthread_table_num -= 1; + + // Avoid upsetting leak detectors. + if (pthread_table_num == 0) { + free(pthread_table); + pthread_table = NULL; + } } void pthread_exit(void *retval) { - if (!self) - abort(); // not started with pthread_create - self->res = retval; - if (!self->handle) { - // detached case - free(self); - self = NULL; - } + pthread_mutex_lock(&pthread_table_lock); + struct m_thread_info *info = find_thread_info(pthread_self()); + assert(info); // not started with pthread_create, or pthread_join() race + info->res = retval; + if (!info->handle) + remove_thread_info(info); // detached case + pthread_mutex_unlock(&pthread_table_lock); + ExitThread(0); } int pthread_join(pthread_t thread, void **retval) { - if (!thread.info) - abort(); // not started with pthread_create - HANDLE h = thread.info->handle; - if (!h) - abort(); // thread was detached + pthread_mutex_lock(&pthread_table_lock); + struct m_thread_info *info = find_thread_info(thread); + assert(info); // not started with pthread_create, or pthread_join() race + HANDLE h = info->handle; + assert(h); // thread was detached + pthread_mutex_unlock(&pthread_table_lock); + WaitForSingleObject(h, INFINITE); + + pthread_mutex_lock(&pthread_table_lock); + info = find_thread_info(thread); + assert(info); + assert(info->handle == h); CloseHandle(h); if (retval) - *retval = thread.info->res; - free(thread.info); + *retval = info->res; + remove_thread_info(info); + pthread_mutex_unlock(&pthread_table_lock); + return 0; } @@ -160,19 +191,21 @@ int pthread_detach(pthread_t thread) { if (!pthread_equal(thread, pthread_self())) abort(); // restriction of this wrapper - if (!thread.info) - abort(); // not started with pthread_create - if (!thread.info->handle) - abort(); // already deatched - CloseHandle(thread.info->handle); - thread.info->handle = NULL; + + pthread_mutex_lock(&pthread_table_lock); + struct m_thread_info *info = find_thread_info(thread); + assert(info); // not started with pthread_create + assert(info->handle); // already detached + CloseHandle(info->handle); + info->handle = NULL; + pthread_mutex_unlock(&pthread_table_lock); + return 0; } static DWORD WINAPI run_thread(LPVOID lpParameter) { struct m_thread_info *info = lpParameter; - self = info; pthread_exit(info->user_fn(info->user_arg)); abort(); // not reached } @@ -180,20 +213,33 @@ static DWORD WINAPI run_thread(LPVOID lpParameter) int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { - struct m_thread_info *info = calloc(1, sizeof(*info)); - if (!info) - return EAGAIN; - info->user_fn = start_routine; - info->user_arg = arg; - HANDLE h = CreateThread(NULL, 0, run_thread, info, CREATE_SUSPENDED, NULL); - if (!h) { - free(info); - return EAGAIN; + int res = 0; + pthread_mutex_lock(&pthread_table_lock); + void *nalloc = + realloc(pthread_table, (pthread_table_num + 1) * sizeof(pthread_table[0])); + if (!nalloc) { + res = EAGAIN; + goto done; } - info->handle = h; - *thread = (pthread_t){GetThreadId(h), info}; - ResumeThread(h); - return 0; + pthread_table = nalloc; + pthread_table_num += 1; + struct m_thread_info *info = &pthread_table[pthread_table_num - 1]; + *info = (struct m_thread_info) { + .user_fn = start_routine, + .user_arg = arg, + }; + info->handle = CreateThread(NULL, 0, run_thread, info, CREATE_SUSPENDED, + &info->id); + if (!info->handle) { + remove_thread_info(info); + res = EAGAIN; + goto done; + } + *thread = info->id; + ResumeThread(info->handle); +done: + pthread_mutex_unlock(&pthread_table_lock); + return res; } void pthread_set_name_np(pthread_t thread, const char *name) @@ -206,7 +252,7 @@ void pthread_set_name_np(pthread_t thread, const char *name) if (!pSetThreadDescription) return; - HANDLE th = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, thread.id); + HANDLE th = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, thread); if (!th) return; wchar_t wname[80]; |