summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreroen <eroen@occam.eroen.eu>2015-01-06 00:46:08 +0100
committereroen <eroen@occam.eroen.eu>2015-01-06 01:05:56 +0100
commita27f95bb07ecc0137b6d4394fc0a0e7cdd3d2cba (patch)
treea83f805448f9b3ca0f8252e2ca7d1c838cf7616d /app-emulation/wine
parentgmock-1.7.0-r1 - failglob compat (diff)
downloaderoen-a27f95bb07ecc0137b6d4394fc0a0e7cdd3d2cba.tar.gz
eroen-a27f95bb07ecc0137b6d4394fc0a0e7cdd3d2cba.tar.bz2
eroen-a27f95bb07ecc0137b6d4394fc0a0e7cdd3d2cba.zip
wine-staging by NP-Hardass
NOTE: This will not work as-is due to package rename source: https://bugs.gentoo.org/534672#c4
Diffstat (limited to 'app-emulation/wine')
-rw-r--r--app-emulation/wine/files/wine-1.7.28-gstreamer-v4.patch629
1 files changed, 629 insertions, 0 deletions
diff --git a/app-emulation/wine/files/wine-1.7.28-gstreamer-v4.patch b/app-emulation/wine/files/wine-1.7.28-gstreamer-v4.patch
new file mode 100644
index 0000000..fbf930b
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.28-gstreamer-v4.patch
@@ -0,0 +1,629 @@
+From 9e081cd4a04e3326d4927aa082695f15432590e2 Mon Sep 17 00:00:00 2001
+From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
+Date: Thu, 14 Aug 2014 11:49:20 +0200
+Subject: [PATCH] TESTING -- override pthreads to fix gstreamer v4
+
+I believe the code is ready and will work properly now in all cases.
+but please test before cherry picking this patch, and report
+success or failure to me please.
+
+Changes since v1:
+ - Call pthread_yield to make sure that we link against libpthread.
+ This fixes the build on saucy.
+Changes since v2:
+ - Set thread_data->detached before creating the thread to prevent
+ a race condition.
+Changes since v3:
+ - Set thread_data->detached CORRECTLY. Fix a small race between
+ thread creation and pthread_detach.
+---
+ dlls/ntdll/ntdll_misc.h | 3 +
+ dlls/ntdll/thread.c | 307 +++++++++++++++++++++++++++++++++++++--
+ dlls/winegstreamer/glibthread.c | 13 ++
+ libs/wine/loader.c | 7 +
+ libs/wine/wine.map | 6 +
+ loader/Makefile.in | 2 +-
+ loader/main.c | 41 +++++
+ 7 files changed, 362 insertions(+), 17 deletions(-)
+
+diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
+index 4370084..1af819b 100644
+--- a/dlls/ntdll/ntdll_misc.h
++++ b/dlls/ntdll/ntdll_misc.h
+@@ -28,6 +28,7 @@
+ #include "winnt.h"
+ #include "winternl.h"
+ #include "wine/server.h"
++#include "wine/list.h"
+
+ #define MAX_NT_PATH_LENGTH 277
+
+@@ -235,6 +236,8 @@ struct ntdll_thread_data
+ WINE_VM86_TEB_INFO vm86; /* 1fc vm86 private data */
+ void *exit_frame; /* 204 exit frame pointer */
+ #endif
++ struct list entry;
++ BOOL detached;
+ };
+
+ static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
+diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
+index c8461b0..8d5470e 100644
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -33,6 +33,7 @@
+ #ifdef HAVE_SYS_SYSCALL_H
+ #include <sys/syscall.h>
+ #endif
++#include <errno.h>
+
+ #define NONAMELESSUNION
+ #include "ntstatus.h"
+@@ -58,6 +59,7 @@ struct startup_info
+ TEB *teb;
+ PRTL_THREAD_START_ROUTINE entry_point;
+ void *entry_arg;
++ BOOL native_thread;
+ };
+
+ static PEB *peb;
+@@ -202,6 +204,78 @@ static ULONG get_dyld_image_info_addr(void)
+ }
+ #endif /* __APPLE__ */
+
++#ifdef __linux__
++extern typeof(pthread_create) *__glob_pthread_create, *call_pthread_create;
++extern typeof(pthread_join) *__glob_pthread_join, *call_pthread_join;
++extern typeof(pthread_detach) *__glob_pthread_detach, *call_pthread_detach;
++
++static typeof(pthread_create) __hook_pthread_create;
++static typeof(pthread_join) __hook_pthread_join;
++static typeof(pthread_detach) __hook_pthread_detach;
++
++static pthread_mutex_t thread_lock;
++
++static void thread_wrap_init(void)
++{
++ pthread_mutexattr_t attr;
++ pthread_mutexattr_init(&attr);
++ pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
++ pthread_mutex_init(&thread_lock, &attr);
++ pthread_mutexattr_destroy(&attr);
++
++ call_pthread_create = __hook_pthread_create;
++ call_pthread_join = __hook_pthread_join;
++ call_pthread_detach = __hook_pthread_detach;
++}
++
++static TEB *dead_teb;
++static struct list active_list = LIST_INIT(active_list);
++
++static void take_thread_lock(void)
++{
++ int ret = pthread_mutex_lock(&thread_lock);
++ if (ret == EOWNERDEAD)
++ pthread_mutex_consistent(&thread_lock);
++}
++
++static void detach_thread_unlock(TEB *own_teb)
++{
++ struct ntdll_thread_data *thread_data;
++ TEB *teb = dead_teb;
++
++ dead_teb = own_teb;
++
++ pthread_mutex_unlock(&thread_lock);
++ if (!teb)
++ return;
++
++ thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
++ __glob_pthread_join(thread_data->pthread_id, NULL);
++ signal_free_thread(teb);
++}
++
++static void reap_thread(TEB *teb)
++{
++ struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
++ take_thread_lock();
++ if (thread_data->detached)
++ detach_thread_unlock(teb);
++ else {
++ /*
++ * Do not unlock, wait until the thread is thoroughly dead.
++ * This prevents a race condition where detach is called
++ * after the thread has not finished dying yet.
++ */
++ }
++}
++
++#else
++#define __glob_pthread_create pthread_create
++#define __glob_pthread_join pthread_join
++#define __glob_pthread_detach pthread_detach
++#define thread_wrap_init()
++#endif
++
+ /***********************************************************************
+ * thread_init
+ *
+@@ -220,6 +294,7 @@ HANDLE thread_init(void)
+ struct ntdll_thread_data *thread_data;
+ static struct debug_info debug_info; /* debug info for initial thread */
+
++ thread_wrap_init();
+ virtual_init();
+
+ /* reserve space for shared user data */
+@@ -349,14 +424,12 @@ void terminate_thread( int status )
+ pthread_exit( UIntToPtr(status) );
+ }
+
+-
+-/***********************************************************************
+- * exit_thread
+- */
+-void exit_thread( int status )
++static void exit_thread_common( int status )
+ {
++#ifndef __linux__
+ static void *prev_teb;
+ TEB *teb;
++#endif
+
+ if (status) /* send the exit code to the server (0 is already the default) */
+ {
+@@ -380,24 +453,177 @@ void exit_thread( int status )
+
+ pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
+
++#ifndef __linux__
+ if ((teb = interlocked_xchg_ptr( &prev_teb, NtCurrentTeb() )))
+ {
+ struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
+
+ if (thread_data->pthread_id)
+ {
+- pthread_join( thread_data->pthread_id, NULL );
++ __glob_pthread_join( thread_data->pthread_id, NULL );
+ signal_free_thread( teb );
+ }
+ }
++#else
++ reap_thread(NtCurrentTeb());
++#endif
+
+ close( ntdll_get_thread_data()->wait_fd[0] );
+ close( ntdll_get_thread_data()->wait_fd[1] );
+ close( ntdll_get_thread_data()->reply_fd );
+ close( ntdll_get_thread_data()->request_fd );
++}
++
++void exit_thread( int status )
++{
++ exit_thread_common(status);
+ pthread_exit( UIntToPtr(status) );
+ }
+
++#ifdef __linux__
++
++struct unix_arg {
++ void *(*start)(void *);
++ void *arg;
++};
++
++/* dummy used for comparison */
++static DWORD native_unix_start;
++
++static void call_native_cleanup(void *arg)
++{
++ exit_thread_common(0);
++}
++
++static int
++__hook_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
++ void *(*start_routine) (void *), void *parm)
++{
++ NTSTATUS ret;
++ pthread_t tid;
++ size_t stack = 8 * 1024 * 1024;
++ struct unix_arg arg;
++ arg.start = start_routine;
++ arg.arg = parm;
++
++ if (!thread)
++ thread = &tid;
++
++ TRACE("Overriding thread creation!\n");
++ if (attr) {
++ static int once;
++ if (!once++)
++ FIXME("most thread attributes ignored!\n");
++ else
++ WARN("most thread attributes ignored!\n");
++
++ pthread_attr_getstacksize(attr, &stack);
++ }
++
++ ret = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, stack, 0, (void*)&native_unix_start, &arg, NULL, (void*)thread );
++ if (ret != STATUS_SUCCESS)
++ FIXME("ret: %08x\n", ret);
++ switch (ret) {
++ case STATUS_SUCCESS:
++ TRACE("created thread %lx for %p/%p\n", *thread, start_routine, parm);
++ return 0;
++ case STATUS_NO_MEMORY:
++ return ENOMEM;
++ case STATUS_TOO_MANY_OPENED_FILES:
++ return EMFILE;
++ default:
++ ERR("Unhandled ntstatus %08x\n", ret);
++ return ENOMEM;
++ }
++}
++
++static int __hook_pthread_detach(pthread_t thread)
++{
++ struct ntdll_thread_data *thread_data;
++ TEB *teb = NULL;
++
++ if (pthread_equal(thread, pthread_self())) {
++ TRACE("Detached self: %lx\n", pthread_self());
++ ntdll_get_thread_data()->detached = 1;
++ return 0;
++ }
++
++ take_thread_lock();
++ LIST_FOR_EACH_ENTRY(thread_data, &active_list, typeof(*thread_data), entry) {
++ if (pthread_equal(thread_data->pthread_id, thread)) {
++ teb = CONTAINING_RECORD(thread_data, typeof(*teb), SpareBytes1);
++
++ list_remove(&thread_data->entry);
++ if (!pthread_tryjoin_np(thread, NULL)) {
++ detach_thread_unlock(NULL);
++ TRACE("Thread %lx was dead, cleaning up\n", thread);
++ signal_free_thread(teb);
++ return 0;
++ }
++ thread_data->detached = 1;
++ break;
++ }
++ }
++ detach_thread_unlock(NULL);
++ if (!teb)
++ TRACE("Could not find thread %lx to detach\n", thread);
++ else
++ TRACE("Changed thread %lx to detached\n", thread);
++ return teb ? 0 : ESRCH;
++}
++
++static int __hook_pthread_join(pthread_t thread, void **retval)
++{
++ struct ntdll_thread_data *thread_data, *t2;
++ int ret = ESRCH;
++
++ if (pthread_equal(thread, pthread_self()))
++ return EDEADLK;
++
++ take_thread_lock();
++ LIST_FOR_EACH_ENTRY(thread_data, &active_list, typeof(*thread_data), entry) {
++ TEB *teb = CONTAINING_RECORD(thread_data, typeof(*teb), SpareBytes1);
++
++ if (pthread_equal(thread, thread_data->pthread_id)) {
++
++ ret = pthread_tryjoin_np(thread, retval);
++ if (!ret) {
++ TRACE("Thread %lx was dead fastpath, cleaning up\n", thread);
++ goto free;
++ }
++ detach_thread_unlock(NULL);
++
++ ret = __glob_pthread_join(thread, retval);
++ if (ret) {
++ TRACE("Thread %lx join failed with %i, ignoring\n", thread, ret);
++ return ret;
++ }
++
++ take_thread_lock();
++ /* Check if someone else freed the thread yet */
++ LIST_FOR_EACH_ENTRY(t2, &active_list, typeof(*thread_data), entry)
++ if (t2 == thread_data) {
++ TRACE("Cleaning up after successful join\n");
++ goto free;
++ }
++ TRACE("No clean up after successful join, multiple pthread_join's?\n");
++ break;
++
++free:
++ list_remove(&thread_data->entry);
++ detach_thread_unlock(NULL);
++ signal_free_thread(teb);
++ return 0;
++ }
++ }
++
++ detach_thread_unlock(NULL);
++ if (ret)
++ TRACE("failed with %i\n", ret);
++ return ret;
++}
++
++#endif
+
+ /***********************************************************************
+ * start_thread
+@@ -426,9 +652,19 @@ static void start_thread( struct startup_info *info )
+ if (TRACE_ON(relay))
+ DPRINTF( "%04x:Starting thread proc %p (arg=%p)\n", GetCurrentThreadId(), func, arg );
+
+- call_thread_entry_point( (LPTHREAD_START_ROUTINE)func, arg );
+-}
++#ifdef __linux__
++ if (info->native_thread) {
++ void *(*start)(void*) = (void*)func;
+
++ FIXME("Started native thread %08x\n", GetCurrentThreadId());
++ pthread_cleanup_push(call_native_cleanup, NULL);
++ pthread_exit(start(arg));
++ pthread_cleanup_pop(1);
++ return;
++ }
++#endif
++ call_thread_entry_point( (LPTHREAD_START_ROUTINE)func, arg );
++}
+
+ /***********************************************************************
+ * RtlCreateUserThread (NTDLL.@)
+@@ -440,14 +676,13 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
+ HANDLE *handle_ptr, CLIENT_ID *id )
+ {
+ sigset_t sigset;
+- pthread_t pthread_id;
+ pthread_attr_t attr;
+ struct ntdll_thread_data *thread_data;
+ struct startup_info *info = NULL;
+ HANDLE handle = 0, actctx = 0;
+ TEB *teb = NULL;
+ DWORD tid = 0;
+- int request_pipe[2];
++ int request_pipe[2], ret;
+ NTSTATUS status;
+
+ if (process != NtCurrentProcess())
+@@ -472,10 +707,14 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
+ if (handle_ptr) *handle_ptr = wine_server_ptr_handle( result.create_thread.handle );
+ else NtClose( wine_server_ptr_handle( result.create_thread.handle ));
+ }
++ TRACE("CreateThread for other process returns %08x\n", result.create_thread.status);
+ return result.create_thread.status;
+ }
+
+- if (server_pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
++ if (server_pipe( request_pipe ) == -1) {
++ TRACE("CreateThread cannot create request pipe: %m\n");
++ return STATUS_TOO_MANY_OPENED_FILES;
++ }
+ wine_server_send_fd( request_pipe[0] );
+
+ SERVER_START_REQ( new_thread )
+@@ -496,12 +735,16 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
+ if (status)
+ {
+ close( request_pipe[1] );
++ TRACE("CreateThread server request failed with %08x\n", status);
+ return status;
+ }
+
+ pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
+
+- if ((status = signal_alloc_thread( &teb ))) goto error;
++ if ((status = signal_alloc_thread( &teb ))) {
++ TRACE("CreateThread signal thread allocation failed with %08x\n", status);
++ goto error;
++ }
+
+ teb->Peb = NtCurrentTeb()->Peb;
+ teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId());
+@@ -524,32 +767,64 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
+
+ info = (struct startup_info *)(teb + 1);
+ info->teb = teb;
+- info->entry_point = start;
+- info->entry_arg = param;
++#ifdef __linux__
++ info->native_thread = (void*)start == (void*)&native_unix_start;
++ if (info->native_thread) {
++ struct unix_arg *arg = param;
++ info->entry_point = (void*)arg->start;
++ info->entry_arg = arg->arg;
++ } else
++#endif
++ {
++ info->entry_point = start;
++ info->entry_arg = param;
++ }
+
+ thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
++#ifdef __linux__
++ thread_data->detached = !info->native_thread;
++#endif
+ thread_data->request_fd = request_pipe[1];
+ thread_data->reply_fd = -1;
+ thread_data->wait_fd[0] = -1;
+ thread_data->wait_fd[1] = -1;
++ thread_data->entry.next = NULL;
+
+- if ((status = virtual_alloc_thread_stack( teb, stack_reserve, stack_commit ))) goto error;
++ if ((status = virtual_alloc_thread_stack( teb, stack_reserve ?: (8 << 20), stack_commit ?: (1 << 20) ))) {
++ TRACE("Allocating virtual stack for %p (%li/%li) failed with %08x\n", start, stack_reserve, stack_commit, status);
++ goto error;
++ }
+
+ pthread_attr_init( &attr );
+ pthread_attr_setstack( &attr, teb->DeallocationStack,
+ (char *)teb->Tib.StackBase - (char *)teb->DeallocationStack );
+ pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
+ interlocked_xchg_add( &nb_threads, 1 );
+- if (pthread_create( &pthread_id, &attr, (void * (*)(void *))start_thread, info ))
++
++ take_thread_lock();
++ ret = __glob_pthread_create( &thread_data->pthread_id, &attr, (void * (*)(void *))start_thread, info );
++ if (ret)
+ {
++ TRACE("pthread create failed with %i/%m\n", ret);
+ interlocked_xchg_add( &nb_threads, -1 );
+ pthread_attr_destroy( &attr );
+ status = STATUS_NO_MEMORY;
+ goto error;
+ }
++ if (!thread_data->detached)
++ list_add_tail(&active_list, &thread_data->entry);
++ detach_thread_unlock(NULL);
++
+ pthread_attr_destroy( &attr );
+ pthread_sigmask( SIG_SETMASK, &sigset, NULL );
+
++ TRACE("Created thread succesfully, win handle: %04x, pthread: %lx\n", tid, thread_data->pthread_id);
++
++#ifdef __linux__
++ if ((void*)start == (void*)&native_unix_start && id)
++ *(pthread_t*)id = thread_data->pthread_id;
++ else
++#endif
+ if (id) id->UniqueThread = ULongToHandle(tid);
+ if (handle_ptr) *handle_ptr = handle;
+ else NtClose( handle );
+diff --git a/dlls/winegstreamer/glibthread.c b/dlls/winegstreamer/glibthread.c
+index 0d829a0..46e22f4 100644
+--- a/dlls/winegstreamer/glibthread.c
++++ b/dlls/winegstreamer/glibthread.c
+@@ -43,6 +43,7 @@
+ #include <stdlib.h>
+ #include <stdio.h>
+
++#if 0
+ #include "windef.h"
+ #include "winbase.h"
+ #include "winnls.h"
+@@ -388,3 +389,15 @@ void g_thread_impl_init (void)
+ g_thread_self_tls = TlsAlloc ();
+ g_thread_init(&g_thread_functions_for_glib_use_default);
+ }
++
++#else
++
++void g_thread_impl_init (void)
++{
++ static gboolean beenhere = FALSE;
++
++ if (!beenhere++)
++ g_thread_init(NULL);
++}
++
++#endif
+diff --git a/libs/wine/loader.c b/libs/wine/loader.c
+index 7261522..a8c31b9 100644
+--- a/libs/wine/loader.c
++++ b/libs/wine/loader.c
+@@ -73,6 +73,13 @@ char **__wine_main_argv = NULL;
+ WCHAR **__wine_main_wargv = NULL;
+ char **__wine_main_environ = NULL;
+
++#ifdef __linux__
++#include <pthread.h>
++typeof(pthread_create) *call_pthread_create, *__glob_pthread_create;
++typeof(pthread_join) *call_pthread_join, *__glob_pthread_join;
++typeof(pthread_detach) *call_pthread_detach, *__glob_pthread_detach;
++#endif
++
+ struct dll_path_context
+ {
+ unsigned int index; /* current index in the dll path list */
+diff --git a/libs/wine/wine.map b/libs/wine/wine.map
+index 2159fac..fb3b951 100644
+--- a/libs/wine/wine.map
++++ b/libs/wine/wine.map
+@@ -117,6 +117,12 @@ WINE_1.0
+ wine_utf8_mbstowcs;
+ wine_utf8_wcstombs;
+ wine_wctype_table;
++ __glob_pthread_create;
++ call_pthread_create;
++ __glob_pthread_join;
++ call_pthread_join;
++ __glob_pthread_detach;
++ call_pthread_detach;
+
+ local: *;
+ };
+diff --git a/loader/Makefile.in b/loader/Makefile.in
+index 95e4798..a18dd02 100644
+--- a/loader/Makefile.in
++++ b/loader/Makefile.in
+@@ -1,4 +1,4 @@
+-EXTRALIBS = $(PTHREAD_LIBS)
++EXTRALIBS = $(PTHREAD_LIBS) $(DL_LIBS)
+
+ C_SRCS = \
+ main.c \
+diff --git a/loader/main.c b/loader/main.c
+index ac67290..76609e1 100644
+--- a/loader/main.c
++++ b/loader/main.c
+@@ -202,6 +202,45 @@ static int pre_exec(void)
+
+ #endif
+
++#ifdef __linux__
++
++extern typeof(pthread_create) *call_pthread_create, *__glob_pthread_create;
++extern typeof(pthread_detach) *call_pthread_detach, *__glob_pthread_detach;
++extern typeof(pthread_join) *call_pthread_join, *__glob_pthread_join;
++
++int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
++ void *(*start_routine) (void *), void *arg)
++{
++ return call_pthread_create(thread, attr, start_routine, arg);
++}
++
++int pthread_detach(pthread_t thread)
++{
++ return call_pthread_detach(thread);
++}
++
++int pthread_join(pthread_t thread, void **retval)
++{
++ return call_pthread_join(thread, retval);
++}
++
++static void init_thread_hook(void) {
++ call_pthread_create = __glob_pthread_create = dlvsym(RTLD_NEXT, "pthread_create", "GLIBC_2.2.5");
++ if (!__glob_pthread_create)
++ call_pthread_create = __glob_pthread_create = dlvsym(RTLD_NEXT, "pthread_create", "GLIBC_2.1");
++
++ call_pthread_detach = __glob_pthread_detach = dlsym(RTLD_NEXT, "pthread_detach");
++ call_pthread_join = __glob_pthread_join = dlsym(RTLD_NEXT, "pthread_join");
++
++ /* Call a function from libpthread to ensure being linked against it */
++ pthread_yield();
++}
++
++#else
++
++#define init_thread_hook()
++
++#endif
+
+ /**********************************************************************
+ * main
+@@ -211,6 +250,8 @@ int main( int argc, char *argv[] )
+ char error[1024];
+ int i;
+
++ init_thread_hook();
++
+ if (!getenv( "WINELOADERNOEXEC" )) /* first time around */
+ {
+ static char noexec[] = "WINELOADERNOEXEC=1";
+--
+1.7.6.6.GIT
+