summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-08-21 17:49:01 +0200
committerwm4 <wm4@nowhere>2017-08-21 18:14:05 +0200
commit6244c8229f51e968fa5e9e94cf159bc1e1b295c6 (patch)
treeacd4af255e3e164f98d6c25e68951346c1c231b5
parentd431111b0647278d2bc234e9e6551c0b7e6c2b6f (diff)
downloadmpv-win32-thread-simplify.tar.bz2
mpv-win32-thread-simplify.tar.xz
win32: make m_thread_info pointer stablewin32-thread-simplify
Make pthread_table an array of pointers to m_thread_info. The individual m_thread_info pointers are now bound to the lifetime of the corresponding thread. I feel like this is slightly simpler. Much of the pthread_table_lock use can be removed now, since the m_thread_info contents don't need synchronization (they are implicitly protected by thread lifetime and correct API usage). In theory, you could claim that with a lock around everything, bad API use can be detected more easily, but in truth bad API use makes everything racy anyway. This revererts the previous commit, and fixes what broke the code without that commit applied.
-rw-r--r--osdep/win32/pthread.c68
1 files changed, 34 insertions, 34 deletions
diff --git a/osdep/win32/pthread.c b/osdep/win32/pthread.c
index d4a5ddc22a..e98a080ce4 100644
--- a/osdep/win32/pthread.c
+++ b/osdep/win32/pthread.c
@@ -115,7 +115,7 @@ int pthread_cond_wait(pthread_cond_t *restrict cond,
}
static pthread_mutex_t pthread_table_lock = PTHREAD_MUTEX_INITIALIZER;
-static struct m_thread_info *pthread_table;
+static struct m_thread_info **pthread_table;
size_t pthread_table_num;
struct m_thread_info {
@@ -128,61 +128,66 @@ struct m_thread_info {
static struct m_thread_info *find_thread_info(DWORD id)
{
+ pthread_mutex_lock(&pthread_table_lock);
+ struct m_thread_info *res = NULL;
for (int n = 0; n < pthread_table_num; n++) {
- if (id == pthread_table[n].id)
- return &pthread_table[n];
+ if (pthread_table[n]->id == id) {
+ res = pthread_table[n];
+ break;
+ }
}
- return NULL;
+ pthread_mutex_unlock(&pthread_table_lock);
+ return res;
}
static void remove_thread_info(struct m_thread_info *info)
{
+ pthread_mutex_lock(&pthread_table_lock);
+
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;
+ for (int n = 0; n < pthread_table_num; n++) {
+ if (pthread_table[n] == info) {
+ pthread_table[n] = pthread_table[pthread_table_num - 1];
+ pthread_table_num -= 1;
+ info = NULL;
+ }
+ }
+
+ assert(!info); // fails if not found
// Avoid upsetting leak detectors.
if (pthread_table_num == 0) {
free(pthread_table);
pthread_table = NULL;
}
+
+ pthread_mutex_unlock(&pthread_table_lock);
}
void pthread_exit(void *retval)
{
- 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)
{
- 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);
+ assert(info->handle); // thread was detached
- WaitForSingleObject(h, INFINITE);
+ WaitForSingleObject(info->handle, INFINITE);
- pthread_mutex_lock(&pthread_table_lock);
- info = find_thread_info(thread);
- assert(info);
- assert(info->handle == h);
- CloseHandle(h);
+ CloseHandle(info->handle);
if (retval)
*retval = info->res;
remove_thread_info(info);
- pthread_mutex_unlock(&pthread_table_lock);
return 0;
}
@@ -192,24 +197,18 @@ int pthread_detach(pthread_t thread)
if (!pthread_equal(thread, pthread_self()))
abort(); // restriction of this wrapper
- 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)
{
- pthread_mutex_lock(&pthread_table_lock);
- struct m_thread_info *info = find_thread_info(pthread_self());
- assert(info);
- pthread_mutex_unlock(&pthread_table_lock);
-
+ struct m_thread_info *info = lpParameter;
pthread_exit(info->user_fn(info->user_arg));
abort(); // not reached
}
@@ -217,30 +216,31 @@ static DWORD WINAPI run_thread(LPVOID lpParameter)
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
{
- int res = 0;
+ int res = EAGAIN;
pthread_mutex_lock(&pthread_table_lock);
void *nalloc =
realloc(pthread_table, (pthread_table_num + 1) * sizeof(pthread_table[0]));
- if (!nalloc) {
- res = EAGAIN;
+ if (!nalloc)
goto done;
- }
pthread_table = nalloc;
+ struct m_thread_info *info = calloc(sizeof(*info), 1);
+ if (!info)
+ goto done;
+ pthread_table[pthread_table_num] = info;
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, NULL, CREATE_SUSPENDED,
+ 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);
+ res = 0;
done:
pthread_mutex_unlock(&pthread_table_lock);
return res;