diff options
author | 2015-01-06 00:46:08 +0100 | |
---|---|---|
committer | 2015-01-06 01:05:56 +0100 | |
commit | a27f95bb07ecc0137b6d4394fc0a0e7cdd3d2cba (patch) | |
tree | a83f805448f9b3ca0f8252e2ca7d1c838cf7616d /app-emulation/wine | |
parent | gmock-1.7.0-r1 - failglob compat (diff) | |
download | eroen-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.patch | 629 |
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 + |