summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--osdep/win32/include/pthread.h11
-rw-r--r--osdep/win32/pthread.c126
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];