1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-01-08 13:22:53 +02:00

compat/w32pthreads: change pthread_t into pointer to malloced struct

pthread_t is currently defined as a struct, which gets placed into
caller's memory and filled by pthread_create() (which accepts a
pthread_t*).

The problem with this approach is that pthread_join() accepts pthread_t
itself rather than a pointer to it, so it gets a _copy_ of this
structure. This causes non-deterministic failures of pthread_join() to
produce the correct return value - depending on whether the thread
already finished before pthread_join() is called (and thus the copy
contains the correct value), or not (then it contains 0).

Change the definition of pthread_t into a pointer to a struct, that gets
malloced by pthread_create() and freed by pthread_join().

Fixes random failures of fate-ffmpeg-error-rate-fail on Windows after
433cf391f5.

See also [1] for an alternative approach that does not require dynamic
allocation, but relies on an assumption that the pthread_t value
remains in a fixed memory location.

[1] 23829dd2b2

Reviewed-By: Martin Storsjö <martin@martin.st>
This commit is contained in:
Anton Khirnov 2024-12-12 16:04:44 +01:00
parent 17e4746687
commit d2096679d5

View File

@ -50,7 +50,7 @@ typedef struct pthread_t {
void *(*func)(void* arg); void *(*func)(void* arg);
void *arg; void *arg;
void *ret; void *ret;
} pthread_t; } *pthread_t;
/* use light weight mutex/condition variable API for Windows Vista and later */ /* use light weight mutex/condition variable API for Windows Vista and later */
typedef SRWLOCK pthread_mutex_t; typedef SRWLOCK pthread_mutex_t;
@ -74,7 +74,7 @@ typedef CONDITION_VARIABLE pthread_cond_t;
static av_unused THREADFUNC_RETTYPE static av_unused THREADFUNC_RETTYPE
__stdcall attribute_align_arg win32thread_worker(void *arg) __stdcall attribute_align_arg win32thread_worker(void *arg)
{ {
pthread_t *h = (pthread_t*)arg; pthread_t h = (pthread_t)arg;
h->ret = h->func(h->arg); h->ret = h->func(h->arg);
return 0; return 0;
} }
@ -82,21 +82,35 @@ __stdcall attribute_align_arg win32thread_worker(void *arg)
static av_unused int pthread_create(pthread_t *thread, const void *unused_attr, static av_unused int pthread_create(pthread_t *thread, const void *unused_attr,
void *(*start_routine)(void*), void *arg) void *(*start_routine)(void*), void *arg)
{ {
thread->func = start_routine; pthread_t ret;
thread->arg = arg;
ret = av_mallocz(sizeof(*ret));
if (!ret)
return EAGAIN;
ret->func = start_routine;
ret->arg = arg;
#if HAVE_WINRT #if HAVE_WINRT
thread->handle = (void*)CreateThread(NULL, 0, win32thread_worker, thread, ret->handle = (void*)CreateThread(NULL, 0, win32thread_worker, ret,
0, NULL); 0, NULL);
#else #else
thread->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, thread, ret->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, ret,
0, NULL); 0, NULL);
#endif #endif
return !thread->handle;
if (!ret->handle) {
av_free(ret);
return EAGAIN;
}
*thread = ret;
return 0;
} }
static av_unused int pthread_join(pthread_t thread, void **value_ptr) static av_unused int pthread_join(pthread_t thread, void **value_ptr)
{ {
DWORD ret = WaitForSingleObject(thread.handle, INFINITE); DWORD ret = WaitForSingleObject(thread->handle, INFINITE);
if (ret != WAIT_OBJECT_0) { if (ret != WAIT_OBJECT_0) {
if (ret == WAIT_ABANDONED) if (ret == WAIT_ABANDONED)
return EINVAL; return EINVAL;
@ -104,8 +118,9 @@ static av_unused int pthread_join(pthread_t thread, void **value_ptr)
return EDEADLK; return EDEADLK;
} }
if (value_ptr) if (value_ptr)
*value_ptr = thread.ret; *value_ptr = thread->ret;
CloseHandle(thread.handle); CloseHandle(thread->handle);
av_free(thread);
return 0; return 0;
} }